<!DOCTYPE html>
<html lang="zh-CN">
  <head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/tree/4.3.1'>
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
    
  
  <!-- 渲染优化 -->
  <meta http-equiv='x-dns-prefetch-control' content='on' />
  <link rel='dns-prefetch' href='https://cdn.jsdelivr.net'>
  <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
  <link rel="preload" href="/blog/css/first.css" as="style">
  

  <!-- 页面元数据 -->
  
  <title>VUE学习记录 - song的个人博客</title>
  
    <meta name="keywords" content="vue">
  

  

  <!-- feed -->
  

  <!-- import meta -->
  
    
      <meta name="msapplication-TileColor" content="#ffffff">
    
      <meta name="msapplication-config" content="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/browserconfig.xml">
    
      <meta name="theme-color" content="#ffffff">
    
  

  <!-- link -->
  
    <link rel="shortcut icon" type='image/x-icon' href="https://cdn.jsdelivr.net/gh/xaoxuu/assets@master/favicon/favicon.ico">
  

  <!-- import link -->
  
  
  <link rel="apple-touch-icon" sizes="180x180" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/apple-touch-icon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/favicon-32x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/favicon-16x16.png">
  <link rel="manifest" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/site.webmanifest">
  <link rel="mask-icon" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/safari-pinned-tab.svg" color="#5bbad5">
  <link rel="shortcut icon" href="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/favicon/favicon.ico">
  

  
    
<link rel="stylesheet" href="/blog/css/first.css">

  

  
  <link rel="stylesheet" href="/blog/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/blog/css/style.css"></noscript>
  

  <script id="loadcss"></script>

  
<script>
if (/*@cc_on!@*/false || (!!window.MSInputMethodContext && !!document.documentMode))
    document.write(
	'<style>'+
		'html{'+
			'overflow-x: hidden !important;'+
			'overflow-y: hidden !important;'+
		'}'+
		'.kill-ie{'+
			'text-align:center;'+
			'height: 100%;'+
			'margin-top: 15%;'+
			'margin-bottom: 5500%;'+
		'}'+
	'</style>'+
    '<div class="kill-ie">'+
        '<h1><b>抱歉，您的浏览器无法访问本站</b></h1>'+
        '<h3>微软已经于2016年终止了对 Internet Explorer (IE) 10 及更早版本的支持，<br/>'+
        '继续使用存在极大的安全隐患，请使用当代主流的浏览器进行访问。</h3><br/>'+
        '<a target="_blank" rel="noopener" href="https://www.microsoft.com/zh-cn/WindowsForBusiness/End-of-IE-support"><strong>了解详情 ></strong></a>'+
    '</div>');
</script>


<noscript>
	<style>
		html{
			overflow-x: hidden !important;
			overflow-y: hidden !important;
		}
		.kill-noscript{
			text-align:center;
			height: 100%;
			margin-top: 15%;
			margin-bottom: 5500%;
		}
	</style>
    <div class="kill-noscript">
        <h1><b>抱歉，您的浏览器无法访问本站</b></h1>
        <h3>本页面需要浏览器支持（启用）JavaScript</h3><br/>
        <a target="_blank" rel="noopener" href="https://www.baidu.com/s?wd=启用JavaScript"><strong>了解详情 ></strong></a>
    </div>
</noscript>

</head>

  <body>
    

<header id="l_header" class="l_header auto shadow blur show" style='opacity: 0' >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fas fa-comments fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
          <li><a id="s-toc" class="s-toc fas fa-list fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/blog/'>
          
            <img no-lazy class='logo' src='https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/blog/Logo-NavBar@3x.png'/>
          
          
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/blog/
                  
                  
                  
                    id="blog"
                  >
                  <i class='fas fa-rss fa-fw'></i>博客
                </a>
                
              </li>
            
          
          
				</ul>
			</div>

      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fas fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="Search..." />
        </form>
      </div>

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fas fa-search fa-fw" target="_self" href='javascript:void(0)'></a></li>
				
				<li>
          <a class="s-menu fas fa-bars fa-fw" target="_self" href='javascript:void(0)'></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/blog/
                  
                  
                  
                    id="blog"
                  >
                  <i class='fas fa-rss fa-fw'></i>博客
                </a>
                
              </li>
            
          
            
          </ul>
        </li>
			</ul>
		</div>
	</div>
  </div>
</header>

    <div id="l_body">
      <div id="l_cover">
  
    
        <div id="full" class='cover-wrapper py dock' style="display: none;">
          
            <div class='cover-bg lazyload placeholder' data-bg="https://bing.ioliu.cn/v1/rand?w=1920&h=1200"></div>
          
          <div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">song的个人博客</p>
    
    
  </div>
  <div class='bottom'>
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="/blog/v4/getting-started/"
              
              
              id="blogv4getting-started">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f5c3.svg'><p>文档</p>
            </a>
          
            <a href="/blog/faqs/"
              
              
              id="blogfaqs">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f516.svg'><p>帮助</p>
            </a>
          
            <a href="/blog/examples/"
              
              
              id="blogexamples">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f396.svg'><p>示例</p>
            </a>
          
            <a href="/blog/contributors/"
              
              
              id="blogcontributors">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f389.svg'><p>社区</p>
            </a>
          
            <a href="/blog/archives/"
              
              
              id="blogarchives">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f4f0.svg'><p>博客</p>
            </a>
          
            <a target="_blank" rel="noopener" href="https://github.com/volantis-x/hexo-theme-volantis/"
              
              
              id="https:githubcomvolantis-xhexo-theme-volantis">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f9ec.svg'><p>源码</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

          <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
        </div>
    
  
  </div>

      <div id="safearea">
        <div class="body-wrapper" id="pjax-container">
          

<div class='l_main'>
  <article class="article post white-box reveal md shadow article-type-py" id="py" itemscope itemprop="blogPost">
  


  
    <div class='headimg-div'>
      <a class='headimg-a'>
        <img class='headimg' src='https://z3.ax1x.com/2021/10/30/5xiucQ.jpg'/>
      </a>
    </div>
  
  <div class="article-meta" id="top">
    
    
    
      <h1 class="title">
        VUE学习记录
      </h1>
      <div class='new-meta-box'>
        
          
            
<div class='new-meta-item author'>
  <a class='author' href="/" rel="nofollow">
    <img no-lazy src="">
    <p>请设置文章作者</p>
  </a>
</div>

          
        
          
            
  <div class='new-meta-item category'>
    <a class='notlink'>
      <i class="fas fa-folder-open fa-fw" aria-hidden="true"></i>
      <a class="category-link" href="/blog/categories/vue/">vue</a>
    </a>
  </div>


          
        
          
            <div class="new-meta-item date">
  <a class='notlink'>
    <i class="fas fa-calendar-alt fa-fw" aria-hidden="true"></i>
    <p>发布于：2022年1月30日</p>
  </a>
</div>

          
        
          
            
  <div class="new-meta-item browse leancloud">
    <a class='notlink'>
      
      <div id="lc-pv" data-title="VUE学习记录" data-path="/blog/vuejs.html">
        <i class="fas fa-eye fa-fw" aria-hidden="true"></i>
        <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span>
        次浏览
      </div>
    </a>
  </div>


          
        
      </div>
    
  </div>


  
  
  <h3 id="Webpack"><a href="#Webpack" class="headerlink" title="Webpack"></a>Webpack</h3><p>1.什么是webpack</p>
<p>概念:webpack是前端工程化的具体解决方案</p>
<p>主要功能：它提供了友好的前端模块化开发支持，以及代码压缩混淆，处理浏览器javascript的兼容性，性能优化等强大的功能</p>
<ol>
<li>创建空白项目目录，终端运行npm init -y命令，初始化包管理文件package.json</li>
<li>新建src源代码目录</li>
<li>新建src-&gt;index.html 首页和 index.js脚本文件</li>
<li>初始化首页的基本结构 ,vscode 中是!</li>
<li>运行npm install jquery -S  ,安装Jquery(-S 表示 -save,安装完后要记录到package.json的dependencies节点下)</li>
<li>通过ES6模块化导入Jquery，实现隔行的变色效果</li>
</ol>
<p><strong>dependencies下的包，项目开发和部署后运行都要</strong></p>
<p>index.html</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ul-&gt;li&#123;这是第$个li&#125;*9</span><br></pre></td></tr></table></figure>

<p>index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.ES6的方式导入Jquery,(ES6的默认导入语法)</span></span><br><span class="line"><span class="keyword">import</span> $ <span class="keyword">from</span> <span class="string">&#x27;jquery&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2.定义jqeury的入口函数</span></span><br><span class="line">$(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="comment">//3.实现奇偶行变色 li:odd是选择奇数行</span></span><br><span class="line">    $(<span class="string">&#x27;li:odd&#x27;</span>).css(<span class="string">&#x27;background-color&#x27;</span>,<span class="string">&#x27;red&#x27;</span>)</span><br><span class="line">    <span class="comment">// 偶数行</span></span><br><span class="line">    $(<span class="string">&#x27;li:even&#x27;</span>).css(<span class="string">&#x27;background-color&#x27;</span>,<span class="string">&#x27;blue&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>SyntaxError: Cannot use import statement outside a module</p>
<p>语法太高级浏览器不支持</p>
<h3 id="问题：webpack能否解决高级语法？"><a href="#问题：webpack能否解决高级语法？" class="headerlink" title="问题：webpack能否解决高级语法？"></a>问题：webpack能否解决高级语法？</h3><h3 id="Webpack的基本使用"><a href="#Webpack的基本使用" class="headerlink" title="Webpack的基本使用"></a>Webpack的基本使用</h3><p>在项目中安装webpack</p>
<p>在终端中运行命令，安装webpack</p>
<blockquote>
<p>npm install <a href="mailto:&#x77;&#x65;&#98;&#112;&#97;&#x63;&#x6b;&#64;&#53;&#x2e;&#52;&#x32;&#46;&#49;">&#x77;&#x65;&#98;&#112;&#97;&#x63;&#x6b;&#64;&#53;&#x2e;&#52;&#x32;&#46;&#49;</a> <a href="mailto:&#119;&#101;&#98;&#112;&#x61;&#99;&#107;&#x2d;&#99;&#x6c;&#x69;&#64;&#52;&#x2e;&#x37;&#x2e;&#50;">&#119;&#101;&#98;&#112;&#x61;&#99;&#107;&#x2d;&#99;&#x6c;&#x69;&#64;&#52;&#x2e;&#x37;&#x2e;&#50;</a> -D</p>
</blockquote>
<p>-D表示把信息记录到package.json的devDependencies节点下</p>
<p><strong>devDependencies下的包，项目开发时使用</strong></p>
<p>在项目中配置webpack</p>
<p>1.在项目根目录中，创建名为webpack.config.js的webpack配置文件，并初始化如下的配置：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">module.exports = &#123;</span><br><span class="line">	mode: &#x27;development&#x27; //mode用来指定构建模式，可选值有development和production</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2.在package.json的script节点下，新增dev脚本如下:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&quot;scripts&quot;:&#123;</span><br><span class="line">	&quot;dev&quot;: &quot;webpack&quot; //script节点下的脚本，可以通过npm run执行 ，例如npm run dev</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>3.在终端中运行npm run dev命令,启动webpack进行项目的打包构建（执行这个命令实际上是执行了webpack命令）</p>
<p>运行后在项目目录生成了dist文件夹下的main.js</p>
<p>在index.html中导入main.js,运行index.html文件,显示了隔行列表颜色不同的效果</p>
<h3 id="代码压缩"><a href="#代码压缩" class="headerlink" title="代码压缩"></a>代码压缩</h3><blockquote>
<p>修改webpack.config.js里面的mode属性: 修改为production</p>
</blockquote>
<p>打包时间变长了，开发时候还是使用development</p>
<p>webpack命令默认会处理src下的index.js文件，输出为dist下面的main.js文件</p>
<h3 id="自定义打包的入口和出口"><a href="#自定义打包的入口和出口" class="headerlink" title="自定义打包的入口和出口"></a>自定义打包的入口和出口</h3><p>可以修改webpack默认处理的文件，比如要处理index111.js文件</p>
<p>在webpack.config.js配置文件中,通过entry节点指定打包的入口，通过output节点指定打包的入口。</p>
<p>实例代码如下：</p>
<p>index.js改名为index1.js</p>
<p>配置webpack.config.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入node.js的中的专门操作路径的模块</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用Node.js中的导出语法，向外到处一个webpack的配置对象</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">    <span class="attr">entry</span>: path.join(__dirname, <span class="string">&#x27;./src/index.js&#x27;</span>),  <span class="comment">//打包入口的路径</span></span><br><span class="line">    <span class="attr">output</span>: &#123;</span><br><span class="line">        <span class="attr">path</span>: path.join(__dirname, <span class="string">&#x27;./dist&#x27;</span>),  <span class="comment">//输出文件的存放路径</span></span><br><span class="line">        <span class="attr">filename</span>: <span class="string">&#x27;bundle.js&#x27;</span>  <span class="comment">//输出的文件的名称</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">//mode用来指定构建模式，可选值有development和production</span></span><br><span class="line">    <span class="attr">mode</span>: <span class="string">&#x27;development&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再次运行npm run dev</p>
<blockquote>
<p>asset main.js 324 KiB [emitted] (name: main)<br>runtime modules 937 bytes 4 modules<br>cacheable modules 282 KiB<br>  ./src/index1.js 307 bytes [built] [code generated]<br>  ./node_modules/jquery/dist/jquery.js 282 KiB [built] [code generated]<br>webpack 5.42.1 compiled successfully in 495 ms</p>
</blockquote>
<h3 id="问题：每次修改源代码都要打包一次？"><a href="#问题：每次修改源代码都要打包一次？" class="headerlink" title="问题：每次修改源代码都要打包一次？"></a>问题：每次修改源代码都要打包一次？</h3><p>如何实现修改源码保存后即可生成main.js文件</p>
<p>需要通过配置webpack来实现，使用插件来实现，通过安装插件来扩展webpack的功能</p>
<p>常用的插件有：</p>
<p>webpack-dev-server</p>
<p>​        每次修改源码，webpack会自动进行打包和构建</p>
<p>html-webpack-plugin</p>
<p>​        webpack中的html插件，类似于模板引擎</p>
<p>​        可以通过插件自定义index.html页面的内容</p>
<h3 id="webpack-dev-server安装和配置"><a href="#webpack-dev-server安装和配置" class="headerlink" title="webpack-dev-server安装和配置"></a>webpack-dev-server安装和配置</h3><p>运行npm i <a href="mailto:&#x77;&#101;&#98;&#x70;&#x61;&#x63;&#x6b;&#45;&#x64;&#101;&#x76;&#x2d;&#x73;&#x65;&#114;&#x76;&#101;&#114;&#64;&#x33;&#x2e;&#x31;&#x31;&#x2e;&#x32;">&#x77;&#101;&#98;&#x70;&#x61;&#x63;&#x6b;&#45;&#x64;&#101;&#x76;&#x2d;&#x73;&#x65;&#114;&#x76;&#101;&#114;&#64;&#x33;&#x2e;&#x31;&#x31;&#x2e;&#x32;</a> -D</p>
<p>配置webpack-dev-server：</p>
<ol>
<li>修改package.json -&gt; script中的dev命令如下：</li>
</ol>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;scripts&quot;</span>: &#123;</span><br><span class="line">  <span class="attr">&quot;dev&quot;</span>: <span class="string">&quot;webpack serve&quot;</span></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<ol>
<li>再次运行npm run dev命令,重新对项目进行打包</li>
<li>在浏览器中访问<a target="_blank" rel="noopener" href="http://localhsot:8080/">http://localhsot:8080</a> 地址，查看自动打包的效果</li>
</ol>
<p>注意:webpack-dev-server会启动一个实时打包的http服务器</p>
<p>注意：注意安装的版本号</p>
<h3 id="记录一个报错"><a href="#记录一个报错" class="headerlink" title="记录一个报错"></a>记录一个报错</h3><p>安装webpack-dev-server后，修改package.json下的script下的dev为”webpack   serve”</p>
<p>再次运行npm run dev构建项目</p>
<p>报错信息为 npm problem 构建失败  出错行为    “dev”: “webpack serve”</p>
<p>尝试全局安装webpack和webpack-cli，webpack-dev-server</p>
<p>但是无效，（错误示范，不要全局安装webpack，不同版本的项目会构建失败，在项目内局部安装即可）</p>
<h3 id="webpack-dev-server的报错"><a href="#webpack-dev-server的报错" class="headerlink" title="webpack-dev-server的报错"></a>webpack-dev-server的报错</h3><p>启动npm run dev后访问localhost：8080端口（如果电脑上tomcat端口也是8080请关闭，或者修改为其他端口）</p>
<p>显示Cannot GET /</p>
<p>解决：在webpack.config.js内配置doServer,如</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">    <span class="comment">//mode用来指定构建模式，可选值有development和production</span></span><br><span class="line">    <span class="attr">mode</span>: <span class="string">&#x27;development&#x27;</span>,</span><br><span class="line">    <span class="attr">entry</span>: path.join(__dirname, <span class="string">&#x27;./src/index.js&#x27;</span>),  <span class="comment">//打包入口的路径</span></span><br><span class="line">    <span class="attr">output</span>: &#123;</span><br><span class="line">        <span class="attr">path</span>: path.join(__dirname, <span class="string">&#x27;./dist&#x27;</span>),  <span class="comment">//输出文件的存放路径</span></span><br><span class="line">        <span class="attr">filename</span>: <span class="string">&#x27;bundle.js&#x27;</span>  <span class="comment">//输出的</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">devServer</span>: &#123;</span><br><span class="line">        <span class="attr">static</span>: <span class="string">&#x27;../change-rows-color&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="webpack-dev-server启动后无法实时更新页面"><a href="#webpack-dev-server启动后无法实时更新页面" class="headerlink" title="webpack-dev-server启动后无法实时更新页面"></a>webpack-dev-server启动后无法实时更新页面</h3><p>启动后，生成了bundle.js文件，但是在内存中，不是dist文件夹中</p>
<p>在内存中引用bundle.js,在index.html页面引入内存中的文件</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;/bundle.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="html-webpack-plugin"><a href="#html-webpack-plugin" class="headerlink" title="html-webpack-plugin"></a>html-webpack-plugin</h3><p>安装</p>
<blockquote>
<p>npm install <a href="mailto:&#104;&#x74;&#x6d;&#108;&#x2d;&#119;&#x65;&#98;&#112;&#x61;&#x63;&#x6b;&#45;&#x70;&#108;&#117;&#103;&#x69;&#x6e;&#64;&#53;&#46;&#51;&#46;&#x32;">&#104;&#x74;&#x6d;&#108;&#x2d;&#119;&#x65;&#98;&#112;&#x61;&#x63;&#x6b;&#45;&#x70;&#108;&#117;&#103;&#x69;&#x6e;&#64;&#53;&#46;&#51;&#46;&#x32;</a> -D</p>
</blockquote>
<p>1.作用 把index.html页面映射到 localhost:8080端口一打开的位置，其实虚拟文件也是位于项目根目录下</p>
<p>是一个复制出来的在内存中的页面</p>
<p>2.这个插件还会做一件事，在复制出来的页面上自动注入一个脚本</p>
<h3 id="doServer节点"><a href="#doServer节点" class="headerlink" title="doServer节点"></a>doServer节点</h3><p>在webpack.config.js配置文件中，可以通过doServer节点对webpack-dev-server插件进行更多的配置</p>
<p>示例代码如下:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">doServer: &#123;</span><br><span class="line">    <span class="attr">open</span>:<span class="literal">true</span>,        <span class="comment">//初次打包完是否自动打开浏览器</span></span><br><span class="line">    <span class="attr">host</span>: <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>,  <span class="comment">//实时打包所用的主机地址</span></span><br><span class="line">    <span class="attr">port</span>: <span class="number">80</span>,         <span class="comment">//实时打包所使用的端口号</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>注意：凡是修改了webpack.config.js配置文件，或者修改了package.json配置文件，必须重启实时打包的服务器，否者最新的配置文件无法生效。</p>
<h3 id="webpack中的插件"><a href="#webpack中的插件" class="headerlink" title="webpack中的插件"></a>webpack中的插件</h3><p>1.webpack-dev-server</p>
<ul>
<li>类似于node.js阶段用到的nodemon工具</li>
<li>每当修改了源码，webpack会自动进行项目的打包和构建</li>
</ul>
<p>2.html-webpack-plugin</p>
<ul>
<li>webpack中的html插件(类似于一个模板引擎插件)</li>
<li>可以通过此插件自定义index.html页面的内容</li>
</ul>
<h3 id="webpack中的loader"><a href="#webpack中的loader" class="headerlink" title="webpack中的loader"></a>webpack中的loader</h3><h4 id="loader概述"><a href="#loader概述" class="headerlink" title="loader概述"></a>loader概述</h4><p>在实际开发过程中,webpack默认只能打包处理.js后缀的模块，其他非.js后缀名结尾的模块，</p>
<p>webpack默认处理不了，需要调用loader加载器才可以正常打包，否则就会报错！</p>
<p>loader加载器的作用:协作webpack打包处理特定的文件模块。比如：</p>
<ul>
<li>css-loader可以打包处理.css相关的文件</li>
<li>less-loader可以打包处理.less相关的文件</li>
<li>babel-loader可以打包处理webpack无法处理的高级JS语法</li>
</ul>
<p><img src="https://z3.ax1x.com/2021/11/14/I6Yvbn.png" class="lazyload" data-srcset="https://z3.ax1x.com/2021/11/14/I6Yvbn.png" srcset=""></p>
<h4 id="webpack打包处理css文件"><a href="#webpack打包处理css文件" class="headerlink" title="webpack打包处理css文件"></a>webpack打包处理css文件</h4><p>1.运行npm i <a href="mailto:&#x73;&#x74;&#121;&#108;&#x65;&#x2d;&#x6c;&#111;&#97;&#100;&#101;&#114;&#64;&#51;&#x2e;&#x30;&#x2e;&#48;">&#x73;&#x74;&#121;&#108;&#x65;&#x2d;&#x6c;&#111;&#97;&#100;&#101;&#114;&#64;&#51;&#x2e;&#x30;&#x2e;&#48;</a> <a href="mailto:&#x63;&#x73;&#x73;&#45;&#x6c;&#x6f;&#97;&#100;&#101;&#x72;&#64;&#53;&#46;&#50;&#46;&#54;">&#x63;&#x73;&#x73;&#45;&#x6c;&#x6f;&#97;&#100;&#101;&#x72;&#64;&#53;&#46;&#50;&#46;&#54;</a> -D 命令，安装处理css文件的loader</p>
<p>2.在webpack.config.js的module -&gt;  rules数组中，添加loader规则如下</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">        &#123;<span class="attr">test</span>: <span class="regexp">/\.css$/</span>, use: [<span class="string">&#x27;style-loader&#x27;</span>, <span class="string">&#x27;css-loader&#x27;</span>]&#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中：test表示匹配的文件类型，use表示对应要调用的loader</p>
<ul>
<li>注意user数组中指定的loader顺序是固定的</li>
<li>多个loader的调用顺序是：从后往前调用</li>
</ul>
<p>添加css样式，在src下新建 css 目录，新建index.css</p>
<p>1.在webpack中，一切皆为模块，都可以通过ES6语法进行导入和使用</p>
<p>（在js中导入css，我们再次npm的时候就会报错了，显示需要合适的loader处理这种文件）</p>
<p>2.由于代码中包含了index.css文件</p>
<p>3.当webpack发现某个文件处理不了的时候，就会查找webpack.config.js这个配置文件，看module.rules这个数组中是否配置了对应的loader加载器</p>
<p>4.从后往前调用，先转交给最后一个loader(先转交给css-loader)。</p>
<p>5.当css-loader处理完毕后，会把处理的结果，转交给下一个loader(转交给style-loader)。</p>
<p>6.当style-loader处理完毕后，发现没有下一个loader了，于是把处理的结果，转交给webpack</p>
<p>7.webpack把style-loader处理的结果，合并到/dist/bundle.js中，最终生成打包好的文件</p>
<h4 id="less的文件处理方式"><a href="#less的文件处理方式" class="headerlink" title="less的文件处理方式"></a>less的文件处理方式</h4><p>在css中创建less文件(less的特性就是可以嵌套)</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">html</span>, <span class="selector-tag">body</span>, <span class="selector-tag">ul</span> &#123;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">0px</span>;</span><br><span class="line">    <span class="attribute">padding</span>: <span class="number">0px</span>;</span><br><span class="line">    <span class="selector-tag">li</span> &#123;</span><br><span class="line">        <span class="attribute">line-height</span>: <span class="number">30px</span>;</span><br><span class="line">        <span class="attribute">padding-left</span>: <span class="number">20px</span>;</span><br><span class="line">        <span class="attribute">font-size</span>: <span class="number">12px</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果写完保存，终端打包就会报错，提示需要一个合适的loader来处理此类文件</p>
<p>打包处理less</p>
<p>1.运行npm i <a href="mailto:&#x6c;&#x65;&#115;&#115;&#45;&#108;&#x6f;&#97;&#x64;&#101;&#x72;&#x40;&#x31;&#48;&#x2e;&#x30;&#x2e;&#49;">&#x6c;&#x65;&#115;&#115;&#45;&#108;&#x6f;&#97;&#x64;&#101;&#x72;&#x40;&#x31;&#48;&#x2e;&#x30;&#x2e;&#49;</a> <a href="mailto:&#108;&#x65;&#115;&#x73;&#x40;&#x34;&#x2e;&#x31;&#46;&#x31;">&#108;&#x65;&#115;&#x73;&#x40;&#x34;&#x2e;&#x31;&#46;&#x31;</a> -D命令</p>
<p>2.在webpack.config.js的module-rules数组中，添加loader规则如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">    <span class="attr">rules</span>: [</span><br><span class="line">        <span class="comment">// 定义了不同模块对应的loader</span></span><br><span class="line">        &#123; <span class="attr">test</span>: <span class="regexp">/\.css$/</span>, use: [<span class="string">&#x27;style-loader&#x27;</span>, <span class="string">&#x27;css-loader&#x27;</span>]&#125;,</span><br><span class="line">        &#123; <span class="attr">test</span>: <span class="regexp">/\.less$/</span>, use: [<span class="string">&#x27;style-loader&#x27;</span>, <span class="string">&#x27;css-loader&#x27;</span>, <span class="string">&#x27;less-loader&#x27;</span>]&#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="打包处理样式表中与url路径相关的文件"><a href="#打包处理样式表中与url路径相关的文件" class="headerlink" title="打包处理样式表中与url路径相关的文件"></a>打包处理样式表中与url路径相关的文件</h4><p>例子：新建了一个test文件夹(和项目没有任何关系)，新建test.html，导入随便一张图片logo.png</p>
<p>使用base64图片转换工具。转换完成后把字符串复制下来赋值到img标签的src属性</p>
<p>用base64可以防止发起不必要的请求（如果有显示小图标的需求。可以用“精灵图”定位或者base64图）</p>
<p><strong>需求是把/src/images/logo2.png设置给src属性</strong></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 需求是把/src/images/logo2.png设置给src属性 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;&quot;</span> <span class="attr">alt</span>=<span class="string">&quot;&quot;</span> <span class="attr">class</span>=<span class="string">&quot;box&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>1.在index.js中导入图片</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> logo <span class="keyword">from</span> <span class="string">&#x27;./images/logo2.png&#x27;</span></span><br></pre></td></tr></table></figure>

<p>2.给img标签的src动态赋值</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 2.动态赋值</span></span><br><span class="line">$(<span class="string">&#x27;.box&#x27;</span>).attr(<span class="string">&#x27;src&#x27;</span>, logo)</span><br></pre></td></tr></table></figure>

<p>保存后肯定会报错</p>
<blockquote>
<p>ERROR in ./src/images/logo2.png 1:0<br>Module parse failed: Unexpected character ‘�’ (1:0)<br>You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See <a target="_blank" rel="noopener" href="https://webpack.js.org/concepts#loaders">https://webpack.js.org/concepts#loaders</a><br>(Source code omitted for this binary file)<br> @ ./src/index.js 8:0-37 10:22-26</p>
</blockquote>
<p>缺少处理图片的loader</p>
<h4 id="配置加载图片的loader"><a href="#配置加载图片的loader" class="headerlink" title="配置加载图片的loader"></a>配置加载图片的loader</h4><p>安装loader</p>
<p>1.运行npm i <a href="mailto:&#x75;&#x72;&#x6c;&#45;&#108;&#111;&#x61;&#100;&#x65;&#x72;&#x40;&#x34;&#x2e;&#49;&#46;&#49;">&#x75;&#x72;&#x6c;&#45;&#108;&#111;&#x61;&#100;&#x65;&#x72;&#x40;&#x34;&#x2e;&#49;&#46;&#49;</a>  <a href="mailto:&#102;&#x69;&#108;&#x65;&#45;&#x6c;&#x6f;&#97;&#x64;&#x65;&#114;&#x40;&#x36;&#46;&#x32;&#46;&#x30;">&#102;&#x69;&#108;&#x65;&#45;&#x6c;&#x6f;&#97;&#x64;&#x65;&#114;&#x40;&#x36;&#46;&#x32;&#46;&#x30;</a> -D命令</p>
<p>2.在webpack.config.js的module-rules数组中，添加loader规则如下：</p>
<pre><code>module: &#123;  //书友第三方文件模块的匹配规则
    rules: [  //文件后缀名的匹配规则
        // 定义了不同模块对应的loader
        &#123; test: /\.css$/, use: [&#39;style-loader&#39;, &#39;css-loader&#39;]&#125;,
        &#123; test: /\.less$/, use: [&#39;style-loader&#39;, &#39;css-loader&#39;, &#39;less-loader&#39;]&#125;,
        &#123; test: /\.jpg|png|gif$/, use: [&#39;url-loader?limit=22229&#39;]&#125;
    ]
&#125;
</code></pre>
<p>其中?后面的是loader的参数：如果只有一个loader写成字符串也行，多个就数组</p>
<ul>
<li>limit用来指定图片的大小</li>
<li>只有&lt;=limit大小的图片，才会被转换城base64格式的图片</li>
</ul>
<p>配置完，运行npm run dev，显示图片，F12查看源码发现，图片已经转换成base64</p>
<p><img src="https://z3.ax1x.com/2021/11/14/Ic1ufe.png" class="lazyload" data-srcset="https://z3.ax1x.com/2021/11/14/Ic1ufe.png" srcset=""></p>
<p>css和less文件的处理方式：在webpack中一切皆为模块，都可以被转换成类似js的方式来运行、</p>
<h4 id="利用babel-loader转换处理高级的JS语法"><a href="#利用babel-loader转换处理高级的JS语法" class="headerlink" title="利用babel-loader转换处理高级的JS语法"></a>利用babel-loader转换处理高级的JS语法</h4><p>1.webpack只能打包处理一部分的高级javascript语法，对那些webpack无法处理的高级js语法，需要借助babel-loader进行打包处理，比如webpack就无法处理下面的代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.定义了名为info的装饰器</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">info</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 2.为目标添加静态属性</span></span><br><span class="line">    target.info = <span class="string">&#x27;Person info&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3.为Person类应用info装饰器</span></span><br><span class="line">@info</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span></span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4.打印Person类应用的info装饰器</span></span><br><span class="line"><span class="built_in">console</span>.log(Person.info)</span><br></pre></td></tr></table></figure>

<p>启动 npm run dev后报错，信息为</p>
<blockquote>
<p>ERROR in ./src/index.js 27:0<br>Module parse failed: Unexpected character ‘@’ (27:0)<br>You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See <a target="_blank" rel="noopener" href="https://webpack.js.org/concepts#loaders">https://webpack.js.org/concepts#loaders</a><br>|<br>| // 3.为Person类应用info装饰器</p>
<p>@info<br>| class Person {}<br>|</p>
</blockquote>
<p>安装babel-loader相关的包</p>
<p>运行以下命令安装对应的依赖包:</p>
<blockquote>
<p>npm i <a href="mailto:&#x62;&#97;&#x62;&#101;&#108;&#45;&#108;&#x6f;&#x61;&#100;&#101;&#x72;&#x40;&#56;&#46;&#x32;&#x2e;&#x32;">&#x62;&#97;&#x62;&#101;&#108;&#45;&#108;&#x6f;&#x61;&#100;&#101;&#x72;&#x40;&#56;&#46;&#x32;&#x2e;&#x32;</a> @babel/<a href="mailto:&#99;&#111;&#114;&#x65;&#64;&#x37;&#46;&#x31;&#x34;&#x2e;&#54;">&#99;&#111;&#114;&#x65;&#64;&#x37;&#46;&#x31;&#x34;&#x2e;&#54;</a> @babel/<a href="mailto:&#x70;&#108;&#x75;&#x67;&#105;&#x6e;&#x2d;&#112;&#114;&#x6f;&#x70;&#x6f;&#115;&#97;&#108;&#45;&#x64;&#101;&#99;&#x6f;&#x72;&#x61;&#116;&#111;&#114;&#x73;&#x40;&#x37;&#x2e;&#49;&#x34;&#46;&#x35;">&#x70;&#108;&#x75;&#x67;&#105;&#x6e;&#x2d;&#112;&#114;&#x6f;&#x70;&#x6f;&#115;&#97;&#108;&#45;&#x64;&#101;&#99;&#x6f;&#x72;&#x61;&#116;&#111;&#114;&#x73;&#x40;&#x37;&#x2e;&#49;&#x34;&#46;&#x35;</a> -D</p>
</blockquote>
<p>在webpack.config.js的module -&gt;  rules数组中，添加loader规则如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 注意：必须使用exclude指定排除项,应为node_modules目录下的第三方包不需要被打包</span></span><br><span class="line">&#123; <span class="attr">test</span>: <span class="regexp">/\.js$/</span>, use: <span class="string">&#x27;babel-loader&#x27;</span>, <span class="attr">exclude</span>: <span class="regexp">/node_modules/</span> &#125;</span><br></pre></td></tr></table></figure>

<p>配置babel-loader</p>
<p>在项目根目录下，创建名为babel.config.js的配置文件，定义babel的配置项如下:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line"></span><br><span class="line">​	<span class="comment">//声明babel可用的插件</span></span><br><span class="line"></span><br><span class="line">​	plugins: [[<span class="string">&#x27;@babel/plugin-proposal-decorators&#x27;</span>, &#123; <span class="attr">legacy</span>: <span class="literal">true</span> &#125;]]</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>@bebal/plugin-proposal-decorators这个插件能告诉 babel-loader 如何去解析@info高级语法</p>
<h3 id="打包发布"><a href="#打包发布" class="headerlink" title="打包发布"></a>打包发布</h3><p>配置webpack的打包发布</p>
<p>在package.json文件的script节点下，新增build命令如下</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;script&quot;</span>: &#123;</span><br><span class="line">	<span class="attr">&quot;dev&quot;</span>: <span class="string">&quot;webpack serve&quot;</span>,               <span class="comment">// 在开发环境中，运行npm run dev命令</span></span><br><span class="line">    <span class="attr">&quot;build&quot;</span>: <span class="string">&quot;webpack --mode production&quot;</span>  <span class="comment">// 项目发布时，运行build命令</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>–model是一个参数项，用来指定webpack的运行模式，production代表生产环境，会对打包生成的文件进行代码压缩和性能优化</p>
<p>注意：通过–model指定的参数项，会覆盖webpack.config.js中的model选项（dev或者production）</p>
<h4 id="配置自动生成的js文件"><a href="#配置自动生成的js文件" class="headerlink" title="配置自动生成的js文件"></a>配置自动生成的js文件</h4><p>配置build设置，dist中的文件全都生成在根目录，我们希望生成的文件都分别放在他们应该的目录中，比如js文件放在js文件夹中，css文件放在css文件夹中</p>
<p>在webpack.config.js中，这样bundle.js就会生成放在js文件夹中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">output: &#123;</span><br><span class="line">    <span class="attr">path</span>: path.join(__dirname, <span class="string">&#x27;./dist&#x27;</span>),  <span class="comment">//输出文件的存放路径</span></span><br><span class="line">    <span class="attr">filename</span>: <span class="string">&#x27;js/bundle.js&#x27;</span>  <span class="comment">//生成的bundle.js放到js文件夹中</span></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<h4 id="配置图片生成路径"><a href="#配置图片生成路径" class="headerlink" title="配置图片生成路径"></a>配置图片生成路径</h4><p>在url-loader配置中添加参数，使用&amp;分隔参数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123; <span class="attr">test</span>: <span class="regexp">/\.jpg|png|gif$/</span>, use: <span class="string">&#x27;url-loader?limit=470&amp;outputPath=images&#x27;</span>&#125;,</span><br></pre></td></tr></table></figure>

<p>生成文件的时候，旧的文件不会自动删除，需要进行配置自动删除dist文件夹</p>
<h4 id="配置自动删除dist"><a href="#配置自动删除dist" class="headerlink" title="配置自动删除dist"></a>配置自动删除dist</h4><p>为了每次打包发布时自动清理掉dist目录中的旧文件，可以安装并配置clean-webpack-plugin插件：</p>
<p>安装：npm install –save-dev clean-webpack-plugin</p>
<p>配置，如果有plugins数组，直接加在后面</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; CleanWebpackPlugin &#125; = <span class="built_in">require</span>(<span class="string">&#x27;clean-webpack-plugin&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> webpackConfig = &#123;</span><br><span class="line">    <span class="attr">plugins</span>: [</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * All files inside webpack&#x27;s output.path directory will be removed once, but the</span></span><br><span class="line"><span class="comment">         * directory itself will not be. If using webpack 4+&#x27;s default configuration,</span></span><br><span class="line"><span class="comment">         * everything under &lt;PROJECT_DIR&gt;/dist/ will be removed.</span></span><br><span class="line"><span class="comment">         * Use cleanOnceBeforeBuildPatterns to override this behavior.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * During rebuilds, all webpack assets that are not used anymore</span></span><br><span class="line"><span class="comment">         * will be removed automatically.</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * See `Options and Defaults` for information</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">new</span> CleanWebpackPlugin(),</span><br><span class="line">    ],</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = webpackConfig;</span><br></pre></td></tr></table></figure>

<p>重新npm run build ，发现自动删除已经生效</p>
<h3 id="webpack最后一个知识点SourceMap"><a href="#webpack最后一个知识点SourceMap" class="headerlink" title="webpack最后一个知识点SourceMap"></a>webpack最后一个知识点SourceMap</h3><p>1.什么是SourceMap ?</p>
<p><strong>SourceMap是一个信息文件，里面储存着位置信息</strong>。也就是说，SourceMap文件中储存着压缩混淆后的代码，所对应的转换前的位置。</p>
<p>有了它，出错的时候，除错工具将直接显示原始代码，而不是转换后的代码，能够极大方便后期的调试</p>
<p>比如：</p>
<p><strong>我们用开发模式运行项目npm run dev 写错的代码错误，提示不是相应的源代码的行号，而是生成的文件中的行号</strong></p>
<p>为了方便程序员调试错误，需要去配置SourceMap</p>
<p>2.默认配置的SourceMap配置是记录生成的文件的行号，而不是源代码的行号，所以导致报错信息和源代码行号不一致的问题</p>
<p>3.配置解决默认SourceMap的问题</p>
<p>在开发环境下，在webpack.config.js中添加如下的配置，即可保证运行时报错行数与源代码行数一致</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//mode用来指定构建模式，可选值有development和production</span></span><br><span class="line"><span class="attr">mode</span>: <span class="string">&#x27;development&#x27;</span>,</span><br><span class="line"><span class="comment">// eval-source-map仅限在开发模式下使用，不建议在生产环境中使用</span></span><br><span class="line"><span class="comment">// 此项生产的SourceMap能够保证运行时报错的行数与源代码的行数保持一致</span></span><br><span class="line"><span class="attr">devtool</span>: <span class="string">&#x27;eval-source-map&#x27;</span>,</span><br></pre></td></tr></table></figure>

<p>2.发布项目的时候建议关闭SourceMap</p>
<p>发布的时候，关闭（注释）Source Map后，重新运行npm run build ，打包发布。运行</p>
<p>在生产环境下，省略devtool选项，则最终生成的文件中不包含Source Map，防止源代码通过报错的形式暴露</p>
<p>4.1只定位行数不暴露源码</p>
<p>在生产环境下，如果只定位报错的具体行数，且不像暴露代码，此时可以将devtool的值设置为</p>
<blockquote>
<p><strong>nosources-source-map</strong></p>
<p>实际效果报错时，点击报错代码不会定位到行数</p>
</blockquote>
<p>如果点击控制台的信息会显示</p>
<blockquote>
<p>无法加载webpack://change-rows-color/./src/index.js 的内容(HTTP 错误: 状态代码 404，net::ERR_UNKNOWN_URL_SCHEME)</p>
</blockquote>
<p>这样就提高的代码的安全性</p>
<h3 id="SourceMap的最佳实践"><a href="#SourceMap的最佳实践" class="headerlink" title="SourceMap的最佳实践"></a>SourceMap的最佳实践</h3><p>1.在开发环境下</p>
<ul>
<li>建议把devtool的值设置为eval-source-map</li>
<li>好处：可以精准定位到具体的错误行</li>
</ul>
<p>2.在生产环境下</p>
<ul>
<li>建议关闭SourceMap或将devtool的值设置为nosources-source-map</li>
<li>好处：防止源码泄露，提高网站的安全性</li>
</ul>
<h4 id="ES6默认的导出方式"><a href="#ES6默认的导出方式" class="headerlink" title="ES6默认的导出方式"></a>ES6默认的导出方式</h4><p>msg.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ES6的默认导出</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="attr">msg</span>: <span class="string">&#x27;Hello Vue!&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>info.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入一个对象</span></span><br><span class="line"><span class="keyword">import</span> msg <span class="keyword">from</span> <span class="string">&#x27;../../mes&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(msg)</span><br></pre></td></tr></table></figure>

<p>在入口文件index.js中加载info.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入src下面的js下的test下的info.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;./js/test/info.js&#x27;</span></span><br></pre></td></tr></table></figure>

<p>这种导入方式如果是多层文件的话，可能会写很多层的**../**</p>
<p>所以建议大家使用 <strong>@</strong> 来代表src源码目录，从外往里找，不要使用  ../ 从里往外找</p>
<p><strong>例如：@/js/test/msg/js</strong></p>
<p>在webpack里使用@表示src需要先去配置</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">resolve: &#123;</span><br><span class="line">    <span class="attr">alias</span>: &#123;</span><br><span class="line">        <span class="comment">// 告诉webpack，程序员写的代码中 @ 表示 src目录</span></span><br><span class="line">        <span class="string">&#x27;@&#x27;</span>: path.join(__dirname, <span class="string">&#x27;./src/&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>info.js导入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 建议使用@代表src目录</span></span><br><span class="line"><span class="keyword">import</span> msg <span class="keyword">from</span> <span class="string">&#x27;@/mes.js&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(msg)</span><br></pre></td></tr></table></figure>

<h3 id="安装VUE浏览器调试工具"><a href="#安装VUE浏览器调试工具" class="headerlink" title="安装VUE浏览器调试工具"></a>安装VUE浏览器调试工具</h3><p>扩展商店下载完后，扩展面板打开开发者工具，打开开发者模式，拖入浏览器窗口进行安装</p>
<p>安装完后需要进行配置才能正常使用，点击扩展工具Vue-devtool的详细信息，打开<strong>允许访问文件</strong>和<strong>收集错误信息</strong></p>
<h3 id="使用Vue-js-devtools"><a href="#使用Vue-js-devtools" class="headerlink" title="使用Vue.js devtools"></a>使用Vue.js devtools</h3><p>安装好插件后，在浏览器的右上角就会有个灰色的Vue图标，在使用了vue的页面中，这个图标就会变成激活状态，变为彩色，打开F12，就可以看到Vue页签了</p>
<h3 id="Vue禁用devtools"><a href="#Vue禁用devtools" class="headerlink" title="Vue禁用devtools"></a>Vue禁用devtools</h3><p>如果页面使用了Vue，插件状态也是激活状态，但是打开F12没有出现Vue页签，那是因为Vue配置中设定了禁用devtools，或者是生产版本默认禁用了</p>
<h4 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h4><p><strong>检查 manifest.json 文件，把 “persistent”: false，改为：true</strong></p>
<p>如果找不到文件位置，可以在文件管理器中直接搜索它的 id ：nhdogjmejiglipccpnnnanhbledajbpd</p>
<p>我的文档位置为 C:\Users\mymsi\AppData\Local\Google\Chrome\User Data\Default\Extensions\nhdogjmejiglipccpnnnanhbledajbpd\4.1.5_0</p>
<h3 id="VUE简介"><a href="#VUE简介" class="headerlink" title="VUE简介"></a>VUE简介</h3><p>1.构建用户界面</p>
<ul>
<li>用vue往html页面中填充数据</li>
</ul>
<p>2.框架</p>
<ul>
<li>框架是一套现成的解决方案</li>
<li>学习vue，就是学习vue框架中规定的用法</li>
<li>vue的指令，组件(UI结构的复用)，路由，Vuex，vue组件库</li>
</ul>
<p> 3.特性</p>
<ul>
<li>数据驱动视图</li>
<li>双性数据绑定</li>
</ul>
<h4 id="数据驱动视图"><a href="#数据驱动视图" class="headerlink" title="数据驱动视图"></a>数据驱动视图</h4><ol>
<li>当页面数据发生变化时，页面会自动重新渲染</li>
<li>数据驱动视图是单向的数据绑定</li>
</ol>
<h4 id="双向数据绑定"><a href="#双向数据绑定" class="headerlink" title="双向数据绑定"></a>双向数据绑定</h4><blockquote>
<p>在网页中，form表单负责采集数据，Ajax负责提交数据</p>
</blockquote>
<ul>
<li>在填写表单时，双向数据绑定可以在不操作DOM的情况下，自动把用户填写的内容同步到数据源中</li>
<li>页面上表单采集的数据发生变化时，会被Vue自动获取到，并更新到js数据中</li>
</ul>
<p>好处：不用手动操作DOM来获取最新的表单值</p>
<p>注意：这里的数据这个概念是存储在js中的数据</p>
<h3 id="MVVM"><a href="#MVVM" class="headerlink" title="MVVM"></a>MVVM</h3><p>MVVM是vue实现数据驱动视图和双向数据绑定的核心原理，MVVM指的是 Model，View，ViewModel,</p>
<p>它把每一个html页面拆分成这三个部分</p>
<p>在MVVM中</p>
<ul>
<li>Model表示当前页面渲染时所依赖的数据源</li>
<li>View表示当前页面渲染的DOM结构</li>
<li>VIewModel表示vue的实例，它是MVVM的核心</li>
</ul>
<p>工作原理：</p>
<p>ViewModel作为MVVM的核心，是它把当前页面的数据源和页面的结构连接在一起。</p>
<p>当数据源发生改变时，会被ViewModel监听到，VM会把最新的数据源自动更新到页面的结构</p>
<p>当表单的值发生变化时，也会被VM监听到，VM会把变化过后最新的值自动同步到Model数据源中</p>
<h3 id="基本使用步骤"><a href="#基本使用步骤" class="headerlink" title="基本使用步骤"></a>基本使用步骤</h3><ol>
<li>导入vue.js的脚本文件</li>
<li>声明一个要被vue控制的dom区域</li>
<li>创建vm实例对象</li>
</ol>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 希望Vue控制这个Dom元素 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span>双大括号 username 双大括号<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 1.导入Vue库文件，全局有了Vue这个构造函数 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;./lib/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 2.创建Vue的实例对象 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//创建Vue的实例对象</span></span></span><br><span class="line"><span class="javascript">        <span class="keyword">const</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">            <span class="comment">// el属性是固定的写法，表示当前vm实例要控制页面上的哪个区域，接受的值是一个选择器</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="comment">// data对象就是要渲染到页面的数据</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">                <span class="attr">username</span>: <span class="string">&#x27;张三&#x27;</span></span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">        &#125;)</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在浏览器工具中可以看到root</p>
<p>这个root就是#app，表示根节点</p>
<h3 id="Vue的指令和过滤器"><a href="#Vue的指令和过滤器" class="headerlink" title="Vue的指令和过滤器"></a>Vue的指令和过滤器</h3><p>1.指令是vue给开发者提供的模板语法，用于辅助开发者渲染页面的基本结构</p>
<p>可分为</p>
<ol>
<li>内容渲染指令</li>
<li>属性绑定指令</li>
<li>事件绑定指令</li>
<li>双向绑定指令</li>
<li>条件渲染指令</li>
<li>列表渲染指令</li>
</ol>
<h4 id="1-内容渲染指令"><a href="#1-内容渲染指令" class="headerlink" title="1.内容渲染指令"></a>1.内容渲染指令</h4><p><strong>内容渲染指令就是辅助开发者渲染DOM元素的文本内容</strong>，常用的有以下三个</p>
<ul>
<li>v-text</li>
<li>双大括号</li>
<li>v-html</li>
</ul>
<h4 id="v-text"><a href="#v-text" class="headerlink" title="v-text"></a>v-text</h4><p>v-text的特性是会覆盖元素内部原有的内容</p>
<p>用法实例：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 希望Vue控制这个Dom元素 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;app&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 把username的值渲染到p标签 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">p</span> <span class="attr">v-text</span>=<span class="string">&quot;username&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">        <span class="comment">&lt;!-- 把gendar的值，渲染到第二个p标签中，默认文本性别会被替换掉 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">p</span> <span class="attr">v-text</span>=<span class="string">&quot;gender&quot;</span>&gt;</span>性别<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!-- 1.导入Vue库文件，全局有了Vue这个构造函数 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;./lib/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 2.创建Vue的实例对象 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//创建Vue的实例对象</span></span></span><br><span class="line"><span class="javascript">        <span class="keyword">const</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">            <span class="comment">// el属性是固定的写法，表示当前vm实例要控制页面上的哪个区域，接受的值是一个选择器</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="comment">// data对象就是要渲染到页面的数据</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">                <span class="attr">username</span>: <span class="string">&#x27;张三&#x27;</span>,</span></span><br><span class="line"><span class="javascript">                <span class="attr">gender</span>: <span class="string">&#x27;男&#x27;</span></span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">        &#125;)</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>页面效果：</p>
<blockquote>
<p>张三</p>
<p>男</p>
</blockquote>
<h4 id="双大括号-双大括号语法（插值）"><a href="#双大括号-双大括号语法（插值）" class="headerlink" title="双大括号 双大括号语法（插值）"></a>双大括号 双大括号语法（插值）</h4><p>vue提供的双大括号双大括号语法，专门用来解决v-text会覆盖默认文本内容的问题，这种 双大括号 双大括号语法，被称为插值表达式(Mustache)</p>
<p>渲染值，并保留原本内容</p>
<p>在开发中用的最多</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">    姓名:双大括号username双大括号</span><br><span class="line"><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p>以上两种方式都不能渲染html元素，所以</p>
<h4 id="v-html"><a href="#v-html" class="headerlink" title="v-html"></a>v-html</h4><p>v-text指令和插值表达式只能渲染纯文本内容，如果要把包含HTML的字符串渲染为页面的html元素，则需要用到v-html这个指令</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-html</span>=<span class="string">&quot;info&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 1.导入Vue库文件，全局有了Vue这个构造函数 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;./lib/vue.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 2.创建Vue的实例对象 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//创建Vue的实例对象</span></span></span><br><span class="line"><span class="javascript">        <span class="keyword">const</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">            <span class="comment">// el属性是固定的写法，表示当前vm实例要控制页面上的哪个区域，接受的值是一个选择器</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">el</span>: <span class="string">&#x27;#app&#x27;</span>,</span></span><br><span class="line"><span class="javascript">            <span class="comment">// data对象就是要渲染到页面的数据</span></span></span><br><span class="line"><span class="javascript">            <span class="attr">data</span>: &#123;</span></span><br><span class="line"><span class="javascript">                <span class="attr">username</span>: <span class="string">&#x27;张三&#x27;</span>,</span></span><br><span class="line"><span class="javascript">                <span class="attr">gender</span>: <span class="string">&#x27;男&#x27;</span>,</span></span><br><span class="line"><span class="javascript">                <span class="attr">info</span>: <span class="string">&#x27;&lt;h4 style=&quot;color: red;font-weight: bold;&quot;&gt;一起学习Vue&lt;/h4&gt;&#x27;</span></span></span><br><span class="line"><span class="javascript">            &#125;</span></span><br><span class="line"><span class="javascript">        &#125;)</span></span><br><span class="line"><span class="javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>开发中推荐用插值</p>
<p> el属性使用的一些注意点：el去控制大元素的div，不要去控制某一个标签或者小元素</p>
<h4 id="2-属性绑定指令"><a href="#2-属性绑定指令" class="headerlink" title="2.属性绑定指令"></a>2.属性绑定指令</h4><p>注意：插值表达式不能用在元素的<strong>属性节点</strong></p>
<p>比如</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;text&quot; placeholder=&quot;双大括号tips双大括号&quot;&gt;</span><br></pre></td></tr></table></figure>

<h4 id="v-bind"><a href="#v-bind" class="headerlink" title="v-bind"></a>v-bind</h4><p>需要为元素的属性动态绑定指令，则需要用到v-bind属性绑定指令，用法如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;text&quot; v-bind:placeholder=&quot;tips&quot;&gt;</span><br><span class="line">&lt;hr&gt;</span><br><span class="line">&lt;img v-bind:src=&quot;photo&quot; alt=&quot;&quot; style=&quot;width: 50px;height: 50px&quot;&gt;</span><br><span class="line">data: &#123;</span><br><span class="line">	tips: &#x27;请输入用户名&#x27;,</span><br><span class="line">	photo: &#x27;https://cn.vuejs.org/images/logo.svg&#x27;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>vue规定v-bind可以写成 ：来简写</p>
<h4 id="插值表达式的运算"><a href="#插值表达式的运算" class="headerlink" title="插值表达式的运算"></a>插值表达式的运算</h4><p>vue提供的渲染语法中除了支持绑定简单的数据值以外，还支持javascript表达式的运算</p>
<p>例如</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">双大括号 number + 1双大括号</span><br><span class="line"></span><br><span class="line">双大括号 ok ? &#x27;YES&#x27; : &#x27;NO&#x27; 双大括号</span><br><span class="line"></span><br><span class="line">双大括号 message.split(&#x27;&#x27;).reverse().join(&#x27;&#x27;) 双大括号</span><br><span class="line"></span><br><span class="line">&lt;div v-bind:id=&quot; &#x27;list-&#x27; + id &quot;&gt;&lt;/div&gt;</span><br><span class="line">里面的属性要加上‘’号，不然会去找data里面的box值</span><br><span class="line">&lt;div v-bind:title=&quot; &#x27;box&#x27; &quot;&gt;这是一个div&lt;/div&gt;</span><br></pre></td></tr></table></figure>

<p>在使用v-bind属性绑定期间，如果绑定的内容需要动态拼接，则字符串的外面应该包裹一个单引号</p>
<h4 id="3-事件绑定指令"><a href="#3-事件绑定指令" class="headerlink" title="3.事件绑定指令"></a>3.事件绑定指令</h4><p>vue提供了事件绑定指令v-on，用来辅助程序员为DOM元素绑定事件监听，语法格式如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;p&gt;count的值是:双大括号count双大括号&lt;/p&gt;</span><br><span class="line">&lt;button v-on:click=&quot;add&quot;&gt;+1&lt;/button&gt;</span><br><span class="line"></span><br><span class="line">data: &#123;</span><br><span class="line">	count: 0</span><br><span class="line">&#125;,</span><br><span class="line">methods: &#123;</span><br><span class="line">	add: function() &#123;</span><br><span class="line">		this.count++</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>ES6语法可以写成add()</p>
<p>vm是vue的实例，输出vm可以看到vue实例，里面包括了定义的函数和属性。</p>
<p>所以可以写成 vm.count ++ </p>
<p>函数add()的传参写法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 绑定事件处理函数时，可以使用（）传递参数 --&gt;</span><br><span class="line">&lt;button v-on:click=&quot;add(2)&quot;&gt;+1&lt;/button&gt;</span><br><span class="line">add(n)&#123;</span><br><span class="line">	this.count+=n</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<p>v-on简写形式： @</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;button @click=&quot;add(2)&quot;&gt;+1&lt;/button&gt;</span><br></pre></td></tr></table></figure>

<p>原生js dom事件有onclick，oninput，onkeyup等原生事件，替换为vue的事件绑定形式后，</p>
<p>分别为：v-on:click，v-on:input，v-on:keyup</p>
<h4 id="事件对象e的使用"><a href="#事件对象e的使用" class="headerlink" title="事件对象e的使用"></a>事件对象e的使用</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;</span><br><span class="line">	&lt;p&gt;count的值是:双大括号count双大括号&lt;/p&gt;</span><br><span class="line">	&lt;!-- 如果是count是偶数，则按钮背景变成红色 --&gt;</span><br><span class="line">	&lt;!-- 使用了e之后，像传递参数n就很难了，所以vue提供了内置变量$event,他就是原生的DOM的事件对象e --&gt;</span><br><span class="line">	&lt;button @click=&quot;add(1,$event)&quot;&gt;+N&lt;/button&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">methods: &#123;</span><br><span class="line">	add(n,e)&#123;</span><br><span class="line">		this.count+=n</span><br><span class="line">		// 判断count的值</span><br><span class="line">		if (this.count % 2 === 0)&#123;</span><br><span class="line">			e.target.style.backgroundColor = &#x27;red&#x27;</span><br><span class="line">		&#125; else&#123;</span><br><span class="line">			e.target.style.backgroundColor = &#x27;&#x27;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="事件修饰符"><a href="#事件修饰符" class="headerlink" title="事件修饰符"></a>事件修饰符</h4><p>事件处理函数中调用event.preventDefault()或event.stopPropagation()是非常常见的需求，因此vue提供了事件修饰符的概念，辅助更好的对事件的触发进行控制常用的五个修饰符如下</p>
<ul>
<li>.prevent     阻止默认行为,如a连接的跳转，表单的提交</li>
<li>.stop          阻止事件冒泡</li>
<li>.capture     以捕捉模式触发当前事件的处理函数</li>
<li>.once         绑定的事件只触发一次</li>
<li>.self           只有在event.target是当前元素自身时触发事件处理函数</li>
</ul>
<p>vue提供的阻止默认事件    js原生方法：e.preventDefault()</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href=&quot;http://www.baidu.com&quot; @click.prevent=&quot;show&quot;&gt;百度&lt;/a&gt;</span><br></pre></td></tr></table></figure>

<p>注意：事件冒泡是如果一个元素嵌套了一个元素，他们都绑定了一个点击事件，如果点击里面的元素，会先触发内元素的点击事件，然后触发外元素的点击事件，如果不想触发外元素的点击事件，就得阻止一下</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;div @click=&quot;divHandler&quot; style=&quot;height: 150px; background-color: orange; padding-left: 100px;line-height: 150px&quot;&gt;</span><br><span class="line">	&lt;button @click.stop=&quot;btnHandler&quot;&gt;按钮&lt;/button&gt;</span><br><span class="line">    &lt;!-- Vue方式阻止冒泡 --&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">	const vm = new Vue(&#123;</span><br><span class="line">		el: &#x27;#app&#x27;,</span><br><span class="line">         data: &#123;&#125;,</span><br><span class="line">         methods: &#123;</span><br><span class="line">         	divHandler()&#123;</span><br><span class="line">            	console.log(&quot;divHandler&quot;)</span><br><span class="line">            &#125;,</span><br><span class="line">            btnHandler()&#123;</span><br><span class="line">		       //e.stopPropagation()  //js原生方式阻止事件冒泡</span><br><span class="line">                console.log(&quot;btnHandler&quot;)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h4 id="4-按钮修饰符"><a href="#4-按钮修饰符" class="headerlink" title="4.按钮修饰符"></a>4.按钮修饰符</h4><p>keyup.esc 按下esc键时触发事件，监听键盘输入事件</p>
<p>操作e.target.value = ‘ ‘   ， 清空输入框</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;</span><br><span class="line">	&lt;input type=&quot;text&quot; @keyup.esc=&quot;clearInput&quot;&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">const vm = new Vue(&#123;</span><br><span class="line">	el: &#x27;#app&#x27;,</span><br><span class="line">    data: &#123; &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">		clearInput(e) &#123;</span><br><span class="line">			console.log(&quot;触发了clear方法&quot;)</span><br><span class="line">			e.target.value = &#x27;&#x27;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>keyup.enter</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- keyup监听键盘输入事件 按下enter按钮触发的事件 --&gt;</span><br><span class="line">&lt;input type=&quot;text&quot; @keyup.enter=&quot;clearInput&quot;&gt;</span><br></pre></td></tr></table></figure>

<h4 id="5-双向数据绑定指令"><a href="#5-双向数据绑定指令" class="headerlink" title="5.双向数据绑定指令"></a>5.双向数据绑定指令</h4><p>v-model双向数据绑定指令，在不操作dom的前提下，快速获取表单的值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;</span><br><span class="line">&lt;p&gt;用户的名字是：双大括号username双大括号&lt;/p&gt;</span><br><span class="line">&lt;input type=&quot;text&quot; v-model=&quot;username&quot;&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&lt;script src=&quot;./lib/vue.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">    const vm = new Vue(&#123;</span><br><span class="line">        el: &#x27;#app&#x27;,</span><br><span class="line">        data: &#123; </span><br><span class="line">            username: &#x27;张三&#x27;</span><br><span class="line">        &#125;,</span><br><span class="line">        methods: &#123;</span><br><span class="line">            </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>v-bind（：）也可以绑定数据，不过是单向的</p>
<p>只有表单元素才能使用v-model指令(输入框input，textarea，select)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;select v-model=&quot;city&quot;&gt;</span><br><span class="line">       &lt;option value=&quot;&quot;&gt;请选择城市&lt;/option&gt;</span><br><span class="line">       &lt;option value=&quot;1&quot;&gt;广州&lt;/option&gt;</span><br><span class="line">       &lt;option value=&quot;2&quot;&gt;上海&lt;/option&gt;</span><br><span class="line">       &lt;option value=&quot;3&quot;&gt;广州&lt;/option&gt;</span><br><span class="line">   &lt;/select&gt;</span><br><span class="line">   &lt;/div&gt;</span><br><span class="line">&lt;!-- city默认值是空，默认选择了第一项，如果给一个默认值是2，那么默认会选中上海 --&gt;</span><br><span class="line">   </span><br><span class="line">   &lt;script src=&quot;./lib/vue.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">   &lt;script&gt;</span><br><span class="line">       const vm = new Vue(&#123;</span><br><span class="line">           el: &#x27;#app&#x27;,</span><br><span class="line">           data: &#123; </span><br><span class="line">               username: &#x27;张三&#x27;,</span><br><span class="line">               city: &#x27;&#x27;</span><br><span class="line">           &#125;,</span><br><span class="line">           methods: &#123;</span><br><span class="line">               </span><br><span class="line">           &#125;</span><br><span class="line">       &#125;)</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<table>
<thead>
<tr>
<th align="center">修饰符</th>
<th align="center">作用</th>
<th align="center">实例</th>
</tr>
</thead>
<tbody><tr>
<td align="center">.number</td>
<td align="center">自动将用户的输入值转为数值类型</td>
<td align="center"><inupt v-model.number="age" /></td>
</tr>
<tr>
<td align="center">.trim</td>
<td align="center">自动过滤用户输入首尾的空格</td>
<td align="center"><inupt v-model.trim="msg" /></td>
</tr>
<tr>
<td align="center">.lazy</td>
<td align="center">在change时而非input时更新</td>
<td align="center"><inupt v-model.lazy="msg" /></td>
</tr>
</tbody></table>
<p>.number的用法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;text&quot; v-model.number=&quot;n1&quot;&gt;</span><br><span class="line">&lt;input type=&quot;text&quot; v-model.number=&quot;n2&quot;&gt;</span><br><span class="line">&lt;span&gt;双大括号 n1+n2 双大括号&lt;/span&gt;</span><br></pre></td></tr></table></figure>

<p>.trim的用法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;text&quot; v-model.trim=&quot;username&quot;&gt;</span><br><span class="line">  &lt;button @click=&quot;showName&quot;&gt;获取用户名&lt;/button&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">  </span><br><span class="line">  &lt;script src=&quot;./lib/vue.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">  &lt;script&gt;</span><br><span class="line">      const vm = new Vue(&#123;</span><br><span class="line">          el: &#x27;#app&#x27;,</span><br><span class="line">          data: &#123; </span><br><span class="line">              username: &#x27;张三&#x27;,</span><br><span class="line">              n1: 1,</span><br><span class="line">              n2: 2</span><br><span class="line">          &#125;,</span><br><span class="line">          methods: &#123;</span><br><span class="line">              showName() &#123;</span><br><span class="line">                  // 占位符写法，这里不是单引号，是反单引号</span><br><span class="line">                  console.log(`用户名是:&quot;$&#123;this.username&#125;&quot;`)</span><br><span class="line">              &#125;</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>.lazy的用法，比如：每一次修改input框，username的值都会同步过去，有时不需要，只需要关心最终的值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;text&quot; v-model.lazy=&quot;username&quot;&gt;</span><br></pre></td></tr></table></figure>

<p>这样修改input框时，data不会改变了，当焦点离开input框，username的值才会改变</p>
<h4 id="6-条件渲染指令"><a href="#6-条件渲染指令" class="headerlink" title="6.条件渲染指令"></a>6.条件渲染指令</h4><p>辅助按需控制DOM的显示和隐藏，条件渲染有以下两个</p>
<ul>
<li>v-if           动态操作DOM</li>
<li>v-show    动态为元素添加display: none样式</li>
</ul>
<p>示例用法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;</span><br><span class="line">	&lt;p v-if=&quot;networkState === 200&quot;&gt;请求成功 --- 被v-if控制&lt;/p&gt;</span><br><span class="line">	&lt;p v-show=&quot;networkState === 200&quot;&gt;请求成功 --- 被v-show控制&lt;/p&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure>

<p>如果需要频繁隐藏显示，用v-show,  如果一般情况下默认为false，或则很久都不用被展示，可以用v-if</p>
<h4 id="vue的指令和过滤器"><a href="#vue的指令和过滤器" class="headerlink" title="vue的指令和过滤器"></a>vue的指令和过滤器</h4><p>v-else</p>
<p>v-if可以单独使用，或者配合v-else一起使用，注意v-else必须配合v-if一起使用，否则不会被识别</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;div v-if=&quot;type === &#x27;A&#x27;&quot;&gt;优秀&lt;/div&gt;</span><br><span class="line">&lt;div v-else-if=&quot;type === &#x27;B&#x27;&quot;&gt;良好&lt;/div&gt;</span><br><span class="line">&lt;div v-else-if=&quot;type === &#x27;C&#x27;&quot;&gt;一般&lt;/div&gt;</span><br><span class="line">&lt;div v-else&gt;差&lt;/div&gt;</span><br></pre></td></tr></table></figure>



<h4 id="7-列表渲染指令"><a href="#7-列表渲染指令" class="headerlink" title="7.列表渲染指令"></a>7.列表渲染指令</h4><p>v-for可以循环渲染 data中的list</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;ul&gt;</span><br><span class="line">	&lt;li v-for=&quot;item in list&quot;&gt;姓名是: 双大括号item.name双大括号&lt;/li&gt;</span><br><span class="line">&lt;/ul&gt;</span><br></pre></td></tr></table></figure>

<p>v-for中的索引，vue中的v-for还支持第二个参数，即当前项的索引语法格式为：item,index in list</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&lt;table class=&quot;table table-bordered table-hover table-striped&quot;&gt;</span><br><span class="line">        &lt;thead&gt;</span><br><span class="line">            &lt;th&gt;索引&lt;/th&gt;</span><br><span class="line">            &lt;th&gt;id&lt;/th&gt;</span><br><span class="line">            &lt;th&gt;姓名&lt;/th&gt;</span><br><span class="line">        &lt;/thead&gt;</span><br><span class="line">        &lt;tbody&gt;</span><br><span class="line">            &lt;tr v-for=&quot;item,index in list&quot; :key=&quot;item.id&quot; :title=&quot;item.name + index&quot;&gt;</span><br><span class="line">                &lt;td&gt;双大括号index双大括号&lt;/td&gt;</span><br><span class="line">                &lt;td&gt;双大括号item.id双大括号&lt;/td&gt;</span><br><span class="line">                &lt;td&gt;双大括号item.name双大括号&lt;/td&gt;</span><br><span class="line">            &lt;/tr&gt;</span><br><span class="line">        &lt;/tbody&gt;</span><br><span class="line">    &lt;/table&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">    const vm = new Vue(&#123;</span><br><span class="line">        el: &#x27;#app&#x27;,</span><br><span class="line">        data: &#123; </span><br><span class="line">            list:[ //列表数据</span><br><span class="line">                &#123; id:1,name: &#x27;张三&#x27;&#125;,</span><br><span class="line">                &#123; id:2,name: &#x27;李四&#x27;&#125;</span><br><span class="line">            ]</span><br><span class="line">        &#125;,</span><br><span class="line">        methods: &#123;</span><br><span class="line">                </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>注意：用完v-for之后，一定要在后面绑定一个数据的key(id)</p>
<ul>
<li>key规定必须是字符串或者数字类型</li>
<li>必须具有唯一性</li>
<li>建议把数据项id属性的值作为key值</li>
<li>用index作为id无意义</li>
<li>使用v-for指令一定要指定key的值</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;tr v-for=&quot;item,index in list&quot; :key=&quot;item.id&quot; :title=&quot;item.name + index&quot;&gt;</span><br></pre></td></tr></table></figure>

<p>反面例子：012-v-for的key.html</p>
<h4 id="表格综合案例"><a href="#表格综合案例" class="headerlink" title="表格综合案例"></a>表格综合案例</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html lang=&quot;en&quot;&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">  &lt;meta charset=&quot;UTF-8&quot;&gt;</span><br><span class="line">  &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;</span><br><span class="line">  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;</span><br><span class="line">  &lt;title&gt;品牌列表案例&lt;/title&gt;</span><br><span class="line">  &lt;link rel=&quot;stylesheet&quot; href=&quot;./lib/bootstrap.css&quot;&gt;</span><br><span class="line">  &lt;link rel=&quot;stylesheet&quot; href=&quot;./css/brandlist.css&quot;&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">  &lt;div id=&quot;app&quot;&gt;</span><br><span class="line">    &lt;!-- 卡片区域 --&gt;</span><br><span class="line">    &lt;div class=&quot;card&quot;&gt;</span><br><span class="line">      &lt;div class=&quot;card-header&quot;&gt;</span><br><span class="line">        添加品牌</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;div class=&quot;card-body&quot;&gt;</span><br><span class="line">        &lt;!-- 添加品牌的表单区域 --&gt;</span><br><span class="line">        &lt;form&gt;</span><br><span class="line">          &lt;div class=&quot;form-row align-items-center&quot;&gt;</span><br><span class="line">            &lt;div class=&quot;col-auto&quot;&gt;</span><br><span class="line">              &lt;div class=&quot;input-group mb-2&quot;&gt;</span><br><span class="line">                &lt;div class=&quot;input-group-prepend&quot;&gt;</span><br><span class="line">                  &lt;div class=&quot;input-group-text&quot;&gt;品牌名称&lt;/div&gt;</span><br><span class="line">                &lt;/div&gt;</span><br><span class="line">                &lt;input type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;请输入品牌名称&quot;&gt;</span><br><span class="line">              &lt;/div&gt;</span><br><span class="line">            &lt;/div&gt;</span><br><span class="line">            &lt;div class=&quot;col-auto&quot;&gt;</span><br><span class="line">              &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary mb-2&quot;&gt;添加&lt;/button&gt;</span><br><span class="line">            &lt;/div&gt;</span><br><span class="line">          &lt;/div&gt;</span><br><span class="line">        &lt;/form&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">    &lt;!-- 表格区域 --&gt;</span><br><span class="line">    &lt;table class=&quot;table table-bordered table-hover table-striped&quot;&gt;</span><br><span class="line">      &lt;thead&gt;</span><br><span class="line">        &lt;tr&gt;</span><br><span class="line">          &lt;th scope=&quot;col&quot;&gt;#&lt;/th&gt;</span><br><span class="line">          &lt;th scope=&quot;col&quot;&gt;品牌名称&lt;/th&gt;</span><br><span class="line">          &lt;th scope=&quot;col&quot;&gt;状态&lt;/th&gt;</span><br><span class="line">          &lt;th scope=&quot;col&quot;&gt;创建时间&lt;/th&gt;</span><br><span class="line">          &lt;th scope=&quot;col&quot;&gt;操作&lt;/th&gt;</span><br><span class="line">        &lt;/tr&gt;</span><br><span class="line">      &lt;/thead&gt;</span><br><span class="line">      &lt;tbody&gt;</span><br><span class="line">        &lt;tr v-for=&quot;item in list&quot; :key=&quot;item.id&quot;&gt;</span><br><span class="line">          &lt;td&gt;双大括号 item.id 双大括号&lt;/td&gt;</span><br><span class="line">          &lt;td&gt;双大括号 item.name 双大括号&lt;/td&gt;</span><br><span class="line">          &lt;td&gt;</span><br><span class="line">            &lt;div class=&quot;custom-control custom-switch&quot;&gt;</span><br><span class="line">              &lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;customSwitch1&quot; v-model=&quot;item.status&quot;&gt;</span><br><span class="line">              &lt;label class=&quot;custom-control-label&quot; for=&quot;customSwitch1&quot; v-if=&quot;item.status&quot;&gt;已启用&lt;/label&gt;</span><br><span class="line">              &lt;label class=&quot;custom-control-label&quot; for=&quot;customSwitch1&quot; v-else&gt;已禁用&lt;/label&gt;</span><br><span class="line">            &lt;/div&gt;</span><br><span class="line">          &lt;/td&gt;</span><br><span class="line">          &lt;td&gt;双大括号 item.time 双大括号&lt;/td&gt;</span><br><span class="line">          &lt;td&gt;</span><br><span class="line">            &lt;a href=&quot;javascript:;&quot;&gt;删除&lt;/a&gt;</span><br><span class="line">          &lt;/td&gt;</span><br><span class="line">        &lt;/tr&gt;</span><br><span class="line">      &lt;/tbody&gt;</span><br><span class="line">    &lt;/table&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">  &lt;script src=&quot;./lib/vue-2.6.12.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">  &lt;script&gt;</span><br><span class="line">    const vm = new Vue(&#123;</span><br><span class="line">      el: &#x27;#app&#x27;,</span><br><span class="line">      data: &#123;</span><br><span class="line">        list: [</span><br><span class="line">          &#123; id: 1, name: &#x27;宝马&#x27;, status: true, time: new Date() &#125;,</span><br><span class="line">          &#123; id: 2, name: &#x27;奔驰&#x27;, status: true, time: new Date() &#125;,</span><br><span class="line">          &#123; id: 3, name: &#x27;本田&#x27;, status: false, time: new Date() &#125;,</span><br><span class="line">          &#123; id: 4, name: &#x27;丰田&#x27;, status: true, time: new Date() &#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &lt;/script&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure>

<p>v-model指令绑定item.status时会在内部判断绑定的元素类型，比如type=“checkbox” 就会去绑定checked的值</p>
<p>问题：点击后面的开关都会修改第一项的开关值，为什么？</p>
<p>label标签有一个for属性,绑定了id=”cb1”，所以每次更改都改了第一的值，应该动态生成这个值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;cb1&quot; v-model=&quot;item.status&quot;&gt;</span><br><span class="line">&lt;label class=&quot;custom-control-label&quot; for=&quot;cb1&quot; v-if=&quot;item.status&quot;&gt;已启用&lt;/label&gt;</span><br><span class="line">&lt;label class=&quot;custom-control-label&quot; for=&quot;cb1&quot; v-else&gt;已禁用&lt;/label&gt;</span><br></pre></td></tr></table></figure>

<p>改良版</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; :id=&quot;&#x27;cb&#x27;+item.id&quot; v-model=&quot;item.status&quot;&gt;</span><br><span class="line">&lt;label class=&quot;custom-control-label&quot; :for=&quot;&#x27;cb&#x27;+item.id&quot; v-if=&quot;item.status&quot;&gt;已启用&lt;/label&gt;</span><br><span class="line">&lt;label class=&quot;custom-control-label&quot; :for=&quot;&#x27;cb&#x27;+item.id&quot; v-else&gt;已禁用&lt;/label&gt;</span><br></pre></td></tr></table></figure>

<p>删除功能</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href=&quot;javascript:;&quot; @click=&quot;remove(item.id)&quot;&gt;删除&lt;/a&gt;</span><br><span class="line">methods: &#123;</span><br><span class="line">	// 点击删除</span><br><span class="line">    remove(id) &#123;</span><br><span class="line">    // 数组过滤函数，过滤后的数组不包含要删除的元素</span><br><span class="line">    this.list = this.list.filter(item =&gt; item.id != id)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>添加功能</p>
<p>问题：添加按钮是表单里面的，默认行为会提交并刷新表单，要先阻止默认行为</p>
<p>表单有一个submit事件，使用事件修饰符。阻止默认行为后，照样可以触发函数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;form @submit.prevent=&quot;add&quot;&gt;</span><br></pre></td></tr></table></figure>

<h4 id="8-vue2中的过滤器"><a href="#8-vue2中的过滤器" class="headerlink" title="8.vue2中的过滤器"></a>8.vue2中的过滤器</h4><p>过滤器filter是vue为开发者提供的功能，常用于文本的格式化，过滤器可以用在两个地方：插值表达式和v-bind属性绑定</p>
<p>过滤器应该被添加在javascript表达式的尾部，由’管道符’进行调用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 在双花括号中通过管道符调用 capitalize 过滤器,对message的值进行格式化 --&gt;</span><br><span class="line">&lt;P&gt;双大括号 message | capitablize 双大括号&lt;/P&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 在v-bind中通过管道符调用 formatId 过滤器,对rawId的值进行格式化 --&gt;</span><br><span class="line">&lt;div v-bind:id=&quot;rawId | formatId&quot;&gt;&lt;/div&gt;</span><br></pre></td></tr></table></figure>

<p>声明过滤器语法：本质上是一个函数，过滤器必须有一个返回值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;</span><br><span class="line">       &lt;p&gt;message的值是：双大括号 message | capi 双大括号&lt;/p&gt;</span><br><span class="line">   &lt;/div&gt;</span><br><span class="line">   &lt;script src=&quot;./lib/vue-2.6.12.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">   &lt;script&gt;</span><br><span class="line">       const vm = new Vue(&#123;</span><br><span class="line">           el: &#x27;#app&#x27;,</span><br><span class="line">           data: &#123;</span><br><span class="line">               message: &#x27;hello vue&#x27;</span><br><span class="line">           &#125;,</span><br><span class="line">           // 过滤器必须被定义到这个节点下</span><br><span class="line">           // 过滤器形参中永远是管道符前面的值</span><br><span class="line">           filters: &#123;</span><br><span class="line">               capi(val) &#123;</span><br><span class="line">                   // 过滤器一定要有一个返回值，方法：把首字母转成大写，思路，截取第一个转换成大写</span><br><span class="line">                   // 字符串有charAt方法把对应索引的字符取出来</span><br><span class="line">                   const first = val.charAt(0).toUpperCase()</span><br><span class="line">                   const other = val.slice(1)</span><br><span class="line">                   return first + other</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">       &#125;)</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h4 id="8-2私有过滤器和全局过滤器"><a href="#8-2私有过滤器和全局过滤器" class="headerlink" title="8.2私有过滤器和全局过滤器"></a>8.2私有过滤器和全局过滤器</h4><p>定义到filters里面的叫做私有过滤器，全局过滤器（要放到main.js里面去）是</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">// 全局过滤器是 - 独立于每个vm实例以外</span><br><span class="line">// Vue.filter()方法接受两个参数</span><br><span class="line">// 第一个参数是，全局过滤器的 名字</span><br><span class="line">// 第二个参数是，是全局过滤器的 处理函数</span><br><span class="line">Vue.filter(&#x27;capitalize&#x27;,(str) =&gt; &#123;</span><br><span class="line">	return str.charAt(0).toUpperCase() + str.slice(1) + &#x27;~~&#x27;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>用法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;</span><br><span class="line">       &lt;p&gt;message的值是：双大括号 message | capitalize 双大括号&lt;/p&gt;</span><br><span class="line">   &lt;/div&gt;</span><br><span class="line">   &lt;script src=&quot;./lib/vue-2.6.12.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">   &lt;script&gt;</span><br><span class="line"></span><br><span class="line">       // Vue全局过滤器,写在new Vue同级，上面</span><br><span class="line">       Vue.filter(&#x27;capitalize&#x27;, function(str) &#123;</span><br><span class="line">           const first = str.charAt(0).toUpperCase()</span><br><span class="line">           const other = str.slice(1)</span><br><span class="line">           return first + other</span><br><span class="line">       &#125;)</span><br></pre></td></tr></table></figure>

<p>注意：如果全局过滤器和私有过滤器名字一致，此时按照“就近原则”，调用的是私有过滤器</p>
<p>表格综合案例里的时间格式化</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;td&gt;双大括号 item.time | dataFormat 双大括号&lt;/td&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">    // 全局过滤器</span><br><span class="line">    Vue.filter(&#x27;dataFormat&#x27;,function(time)&#123;</span><br><span class="line">      // 对日期进行格式化 YYYY-MM-DD HH:mm:ss</span><br><span class="line">      // 使用day.js插件，直接调用dayjs()得到当前的时间，dayjs(给定的日期时间)得到指定的日期</span><br><span class="line">      const dtStr = dayjs(time).format(&#x27;YYYY-MM-DD HH:mm:ss&#x27;)</span><br><span class="line">      return dtStr</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>可以连续的调用多个过滤器</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;td&gt;双大括号 item.time | filterB | filterA双大括号&lt;/td&gt;</span><br></pre></td></tr></table></figure>

<h4 id="8-3过滤器的参数"><a href="#8-3过滤器的参数" class="headerlink" title="8.3过滤器的参数"></a>8.3过滤器的参数</h4><p>因为过滤器本质上是函数，因此可以接受参数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- arg1和arg2是传输给filterA的参数 --&gt;</span><br><span class="line">&lt;p&gt;双大括号 message | filterA(arg1,arg2) 双大括号&lt;/p&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">    // 过滤器处理函数的形参列表中：</span><br><span class="line">    // 第一个参数，永远都是管道符号前面的待处理的值</span><br><span class="line">    // 第二个参数开始，才是调用过滤器时传递过来的 arg1 和 arg2 参数</span><br><span class="line">    Vue.filter(&#x27;filterA&#x27;,(msg,arg1,arg2) =&gt; &#123;</span><br><span class="line">        // 过滤器的代码</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>vue3建议使用计算属性或方法代替被剔除的过滤器功能</p>
<h4 id="9-侦听器Watch"><a href="#9-侦听器Watch" class="headerlink" title="9.侦听器Watch"></a>9.侦听器Watch</h4><p>watch侦听器允许开发者监视数据的变化，从而针对数据的变化做出特定的操作 </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"> &lt;div id=&quot;app&quot;&gt;</span><br><span class="line">        &lt;input type=&quot;text&quot; v-model=&quot;username&quot;&gt;</span><br><span class="line">        &lt;p&gt;双大括号 username 双大括号&lt;/p&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;script src=&quot;./lib/vue-2.6.12.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">    &lt;script&gt;</span><br><span class="line">        const vm = new Vue(&#123;</span><br><span class="line">            el: &#x27;#app&#x27;,</span><br><span class="line">            data: &#123;</span><br><span class="line">                username: &#x27;&#x27;</span><br><span class="line">            &#125;,</span><br><span class="line">            watch: &#123;</span><br><span class="line">                // 侦听器本质上也是个函数，要侦听哪个数据就用哪个数据名字作为函数名</span><br><span class="line">                // 有两个参数，newVal 变化之后的值 ，oldVal是变化之前的值</span><br><span class="line">                username(newVal,oldVal) &#123;</span><br><span class="line">                    console.log(&#x27;监听到了数据的变化&#x27;)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;)</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>应用场景：判断用户名是否被占用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    const vm = new Vue(&#123;</span><br><span class="line">        el: &#x27;#app&#x27;,</span><br><span class="line">        data: &#123;</span><br><span class="line">            username: &#x27;&#x27;</span><br><span class="line">        &#125;,</span><br><span class="line">        watch: &#123;</span><br><span class="line">            // 侦听器本质上也是个函数，要侦听哪个数据就用哪个数据名字作为函数名</span><br><span class="line">            // 有两个参数，newVal 变化之后的值 ，oldVal是变化之前的值</span><br><span class="line">            username(newVal,oldVal) &#123;</span><br><span class="line">                // 1.调用jQuery 中的Ajax发起请求，判断newVal是否被占用</span><br><span class="line">                $.get(&#x27;https://www.escook.cn/api/finduser/&#x27; + newVal, function(result)&#123;</span><br><span class="line">                    console.log(result)</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>需求：需要一进入这个页面就会执行这个侦听器</p>
<h4 id="侦听器的定义格式"><a href="#侦听器的定义格式" class="headerlink" title="侦听器的定义格式"></a>侦听器的定义格式</h4><p>1.方法格式的侦听器</p>
<ul>
<li>​    缺点1：无法在进入页面时，自动触发</li>
<li>​    缺点2：侦听对象属性无法触发侦听器</li>
</ul>
<p>2.对象格式的侦听器</p>
<ul>
<li>​    好处：通过”immediate”这个选项，让侦听器自动触发</li>
<li>​    好处2：通过deep选项，侦听对象里面的属性</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    const vm = new Vue(&#123;</span><br><span class="line">        el: &#x27;#app&#x27;,</span><br><span class="line">        data: &#123;</span><br><span class="line">            username: &#x27;admin&#x27;</span><br><span class="line">        &#125;,</span><br><span class="line">        watch: &#123;</span><br><span class="line">            // 定义对象格式的侦听器</span><br><span class="line">            username: &#123;</span><br><span class="line">                // 侦听器的处理函数，只要侦听到了username值的变化就会自动触发</span><br><span class="line">                handler(newVal,oldVal) &#123;</span><br><span class="line">                    console.log(newVal, oldVal)</span><br><span class="line">                &#125;,</span><br><span class="line">                // immediate作用是控制侦听器是否默认触发</span><br><span class="line">                // true是一进入页面就触发一次，false是默认值</span><br><span class="line">                immediate: true</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h4 id="深度侦听"><a href="#深度侦听" class="headerlink" title="深度侦听"></a>深度侦听</h4><p>侦听对象的变化</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">        const vm = new Vue(&#123;</span><br><span class="line">            el: &#x27;#app&#x27;,</span><br><span class="line">            data: &#123;</span><br><span class="line">                info: &#123;</span><br><span class="line">                    username: &#x27;admin&#x27;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;,</span><br><span class="line">            watch: &#123;</span><br><span class="line">                info: &#123;</span><br><span class="line">                    handler(newVal) &#123;</span><br><span class="line">                        console.log(newVal)</span><br><span class="line">                    &#125;,</span><br><span class="line">                    // 开启深度侦听,只要对象中任何一个属性发生变化了，都会触发&quot;对象的侦听器&quot;</span><br><span class="line">                    deep: true</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;)</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h3 id="计算属性"><a href="#计算属性" class="headerlink" title="计算属性"></a>计算属性</h3><p>计算属性是指通过一系列运算后，最终得到一个属性值</p>
<p>例子：05-计算属性.html 中 rgb值的复用</p>
<p>这个动态计算出来的属性值可以被模板结构或method方法使用，示例代码如下</p>
<h3 id="ES6-模板字符串"><a href="#ES6-模板字符串" class="headerlink" title="ES6 - 模板字符串"></a>ES6 - 模板字符串</h3><p>return <code>rgb($&#123;this.r&#125;, $&#123;this.g&#125;, $&#123;this.b&#125;)</code></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    var vm = new Vue(&#123;</span><br><span class="line">      el: &#x27;#app&#x27;,</span><br><span class="line">      data: &#123;</span><br><span class="line">        r: 0, g: 0,  b: 0</span><br><span class="line">      &#125;,</span><br><span class="line">      computed: &#123;</span><br><span class="line">          // 所有的计算属性都要定义到computed下面</span><br><span class="line">          // 定义格式：定义成方法的格式</span><br><span class="line">          rgb() &#123; return `rgb($&#123;this.r&#125;, $&#123;this.g&#125;, $&#123;this.b&#125;)` &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      methods: &#123;</span><br><span class="line">        // 点击按钮，在终端显示最新的颜色</span><br><span class="line">        show() &#123;</span><br><span class="line">          console.log(this.rgb)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;);</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>使用计算属性来改造页面，定义好的计算属性是vm里面的一个属性</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"> 	&lt;!-- 专门用户呈现颜色的 div 盒子 --&gt;</span><br><span class="line">  &lt;!-- 在属性身上：代表v-bind属性绑定 --&gt;</span><br><span class="line">  &lt;!-- :style 代表动态绑定一个对象，值是一个&#123; &#125; 样式对象 --&gt;</span><br><span class="line">  &lt;!-- 当前样式对象中，只包含backgroundColor  --&gt;</span><br><span class="line">  &lt;div class=&quot;box&quot; :style=&quot;&#123; backgroundColor: rgb &#125;&quot;&gt;</span><br><span class="line">    双大括号 rgb 双大括号</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">  &lt;button @click=&quot;show&quot;&gt;按钮&lt;/button&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">  // 创建 Vue 实例，得到 ViewModel</span><br><span class="line">  var vm = new Vue(&#123;</span><br><span class="line">    el: &#x27;#app&#x27;,</span><br><span class="line">    data: &#123;</span><br><span class="line">      r: 0, g: 0, b: 0</span><br><span class="line">    &#125;,</span><br><span class="line">    computed: &#123;</span><br><span class="line">      // 所有的计算属性都要定义到computed下面</span><br><span class="line">      // 定义格式：定义成方法的格式,最终要返回一个生成好的字符串</span><br><span class="line">      rgb() &#123;</span><br><span class="line">          return `rgb($&#123;this.r&#125;, $&#123;this.g&#125;, $&#123;this.b&#125;)`</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">      // 点击按钮，在终端显示最新的颜色</span><br><span class="line">      show() &#123;</span><br><span class="line">        console.log(this.rgb)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;);</span><br><span class="line">  console.log(vm)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>好处：</p>
<ol>
<li>实现了代码复用</li>
<li>只要计算属性中依赖的值变化，计算属性会自动更新</li>
</ol>
<h3 id="Axios"><a href="#Axios" class="headerlink" title="Axios"></a>Axios</h3><p><strong>是一个专注于网络请求的库</strong></p>
<p>写法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    // 调用axios的返回值是一个promise对象</span><br><span class="line">    axios(&#123;</span><br><span class="line">        method: &#x27;GET&#x27;,</span><br><span class="line">        url: &#x27;http://www.liulongbin.top:3306/api/getbooks&#x27;</span><br><span class="line">    &#125;).then(function(result)&#123;</span><br><span class="line">        // books里面的的data，才是我们要拿到的数据列表</span><br><span class="line">        console.log(result.data)</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>调用axios的返回值是一个promise对象</strong></p>
<p>axios请求到数据之后，在数据外面套了一层壳，包含了config，data等等东西</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">	config: &#123;&#125;,</span><br><span class="line">	data: &#123;数据&#125;,</span><br><span class="line">	headers: &#123;&#125;,</span><br><span class="line">	request: &#123;&#125;,</span><br><span class="line">	status: XXX,</span><br><span class="line">	statusText: &#x27;&#x27;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="axios传递参数"><a href="#axios传递参数" class="headerlink" title="axios传递参数"></a>axios传递参数</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    // 调用axios的返回值是一个promise对象</span><br><span class="line">    rusult = axios(&#123;</span><br><span class="line">        method: &#x27;GET&#x27;,</span><br><span class="line">        url: &#x27;http://www.liulongbin.top:3306/api/getbooks&#x27;,</span><br><span class="line">        // 一般get请求，参数写到params</span><br><span class="line">        params: &#123;</span><br><span class="line"></span><br><span class="line">        &#125;,</span><br><span class="line">        // 请求体参数</span><br><span class="line">        // 一般post请求，参数写到data里面，比如表单的提交</span><br><span class="line">        data: &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;).then(function(books)&#123;</span><br><span class="line">        // books里面的的data，才是我们要拿到的数据列表</span><br><span class="line">        console.log(books.data)</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>post请求写法，这里使用了原生js写法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;button id=&quot;btnPost&quot;&gt;发起post请求&lt;/button&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 复习一下原生js写法 --&gt;</span><br><span class="line"></span><br><span class="line">&lt;script src=&quot;./lib/axios.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">    // querySelector获取文档中 id=&quot;XXX&quot; 的元素</span><br><span class="line">    // addEventListener() 方法用于向指定元素添加事件句柄,如添加点击事件</span><br><span class="line">    document.querySelector(&#x27;#btnPost&#x27;).addEventListener(&#x27;click&#x27;, function() &#123;</span><br><span class="line">        axios(&#123;</span><br><span class="line">            method: &#x27;POST&#x27;,</span><br><span class="line">            url: &#x27;http://www.liulongbin.top:3006/api/post&#x27;,</span><br><span class="line">            data: &#123;</span><br><span class="line">                name: &#x27;zs&#x27;,</span><br><span class="line">                age: 20</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).then(function(result)&#123;</span><br><span class="line">            console.log(result)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>如果调用某个方法的返回至是Promise实例，则前面可以添加 await，记住方法要在async方法内使用</strong></li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.querySelector(<span class="string">&#x27;#btnPost&#x27;</span>).addEventListener(<span class="string">&#x27;click&#x27;</span>, <span class="keyword">async</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">await</span> axios(&#123;</span><br><span class="line">                <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">                <span class="attr">url</span>: <span class="string">&#x27;http://www.liulongbin.top:3006/api/post&#x27;</span>,</span><br><span class="line">                <span class="attr">data</span>: &#123;</span><br><span class="line">                    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">                    <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params">result</span>)</span>&#123;</span><br><span class="line">                <span class="built_in">console</span>.log(result)</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;)</span><br></pre></td></tr></table></figure>

<p>加上await之后，返回的就是正常的数据了</p>
<h3 id="ES6-解构赋值"><a href="#ES6-解构赋值" class="headerlink" title="ES6 - 解构赋值"></a>ES6 - 解构赋值</h3><p>const result = await axios  赋值语句里面，等于两方都有各个属性，<strong>可以直接用属性赋值</strong>，并且then太累赘可以弃用了，写法如下</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123;data&#125; = <span class="keyword">await</span> axios(&#123;</span><br><span class="line">	<span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">	<span class="attr">url</span>: <span class="string">&#x27;http://www.liulongbin.top:3006/api/post&#x27;</span>,</span><br><span class="line">	<span class="attr">data</span>: &#123;</span><br><span class="line">		<span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">		<span class="attr">age</span>: <span class="number">20</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(data)</span><br></pre></td></tr></table></figure>

<ol>
<li>调用axios之后，使用async / await  进行简化</li>
<li>使用解构赋值，从axios封装的大对象中，把data属性解构出来</li>
<li>把解构出来的data属性，使用冒号进行重命名,一般都重命名为 { data: res }</li>
</ol>
<p>发起get请求, <strong>使用 ：号来重命名</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.querySelector(<span class="string">&#x27;#btnGet&#x27;</span>).addEventListener(<span class="string">&#x27;click&#x27;</span>, <span class="keyword">async</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="comment">// 解构赋值使用 : 重命名</span></span><br><span class="line">	<span class="keyword">const</span> &#123; <span class="attr">data</span>:res &#125; = <span class="keyword">await</span> axios(&#123;</span><br><span class="line">		<span class="attr">method</span>: <span class="string">&#x27;GET&#x27;</span>,</span><br><span class="line">		<span class="attr">url</span>: <span class="string">&#x27;http://www.liulongbin.top:3006/api/getbooks&#x27;</span>,</span><br><span class="line">	&#125;)</span><br><span class="line">	<span class="built_in">console</span>.log(res.data)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h3 id="axios-get和axios-post"><a href="#axios-get和axios-post" class="headerlink" title="axios.get和axios.post"></a>axios.get和axios.post</h3><p>axios.get的使用方法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;button id=&quot;btnGet&quot;&gt;发起get请求&lt;/button&gt;</span><br><span class="line"></span><br><span class="line">    &lt;!-- 原生js写法 --&gt;</span><br><span class="line"></span><br><span class="line">    &lt;script src=&quot;./lib/axios.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">    &lt;script&gt;</span><br><span class="line">        document.querySelector(&#x27;#btnGet&#x27;).addEventListener(&#x27;click&#x27;, async function() &#123;</span><br><span class="line">            // axios.get(&#x27;url地址&#x27;, &#123;</span><br><span class="line">            //     // GET 参数</span><br><span class="line">            //     params: &#123;&#125;</span><br><span class="line">            // &#125;)</span><br><span class="line">            const &#123; data:res &#125; = await axios.get(&#x27;http://www.liulongbin.top:3006/api/getbooks&#x27;,&#123;</span><br><span class="line">                // 如果需要写参数</span><br><span class="line">                params: &#123; id:1 &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">            console.log(res.data)</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>axios.post的写法</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.querySelector(<span class="string">&#x27;#btnPost&#x27;</span>).addEventListener(<span class="string">&#x27;click&#x27;</span>, <span class="keyword">async</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="comment">// axios.post(&#x27;url&#x27;,&#123; /* POST请求体数据 */ &#125;)</span></span><br><span class="line">	<span class="keyword">const</span> &#123; <span class="attr">data</span>:res &#125; = <span class="keyword">await</span> axios.post(<span class="string">&#x27;http://www.liulongbin.top:3006/api/post&#x27;</span>,&#123; <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>, <span class="attr">gender</span>: <span class="string">&#x27;女&#x27;</span> &#125;)</span><br><span class="line">	<span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h3 id="单页面应用"><a href="#单页面应用" class="headerlink" title="单页面应用"></a>单页面应用</h3><p>单页面应用，简称SPA，顾名思义，指的是一个Web页面内只有唯一的一个HTML页面，所有功能和交互都在一个页面中完成</p>
<p>什么是vue-cli</p>
<p>vue-cli是vue.js开发的标准工具，webpack创建工程化的Vue项目的过程</p>
<ul>
<li>使用命令安装</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g @vue/cli</span><br></pre></td></tr></table></figure>

<p>vue -V查看版本号</p>
<p>命令无法使用的话，运行npm config get prefix 命令获取路径，把路径加入到环境变量</p>
<p>运行   ’ vue create 项目名称  ‘ 来创建项目</p>
<p>运行之后会让选择vue2配置还是vue3配置，直接选择最后一个来手动配置</p>
<p>基本要选择的插件大概有:</p>
<ol>
<li>vue版本  （2.x）</li>
<li>Babel （解决js兼容性）</li>
<li>css预处理器  (less)</li>
<li>最后一步是要选择，插件的配置文件，是要放在独立的文件还是一起放在package.json里面,(选择放在独立的文件,package.json只用来放信息)</li>
</ol>
<p>创建完可用的选项</p>
<ul>
<li> cd demo-first</li>
<li> npm run serve</li>
</ul>
<h3 id="项目目录各个文件"><a href="#项目目录各个文件" class="headerlink" title="项目目录各个文件"></a>项目目录各个文件</h3><ul>
<li>babel.config.js （babel配置文件）</li>
<li>package.json  (包配置文件)</li>
</ul>
<p>public下的index就是主页。PS：知识点：index下面有一个<!-- built files will be auto injected -->这个就是插件’html-webpack-plugin’插件注入的bundle.js的位置，可以在浏览器中看源码查看</p>
<p>vue项目中的src目录下的文件构成：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">assets 文件夹 ：静态资源，如css样式，图片资源</span><br><span class="line">components 文件夹 ：组件可复用的ui结构，都要放入components目录</span><br><span class="line">main.js 是项目的入口文件，整个项目要先运行main.js，包括打包都要先打包这个</span><br><span class="line">App.vue 是项目的根组件 </span><br></pre></td></tr></table></figure>

<h3 id="vue项目的运行流程"><a href="#vue项目的运行流程" class="headerlink" title="vue项目的运行流程"></a>vue项目的运行流程</h3><p>在工程化的项目中，vue通过main.js吧App.vue渲染到index.html指定的区域中</p>
<ul>
<li>App.vue用来编写待渲染的模板结构</li>
<li>index.html中要预留一个el区域</li>
<li>main.js把App.vue渲染到index.html所预留的区域中</li>
</ul>
<p><strong>.$mount(‘#app’)的作用和我们指定一个el: ‘#app’ 是一样的</strong></p>
<h3 id="Vue组件开发"><a href="#Vue组件开发" class="headerlink" title="Vue组件开发"></a>Vue组件开发</h3><p>1.什么是vue组件化开发</p>
<p>组件化开发指的是：根据封装的思想，把页面上可重用的UI结构封装成组件，从而方便项目的开发和维护</p>
<p>vue中规定，组件的后缀名是.vue ，App.vue本质上是一个组件</p>
<p>2.vue组件的三个组成部分</p>
<p>分别是</p>
<ul>
<li>template  组件的模板结构</li>
<li>script  组件的javascript行为</li>
<li>style 组件的样式</li>
</ul>
<h4 id="Vue组件之间的父子关系"><a href="#Vue组件之间的父子关系" class="headerlink" title="Vue组件之间的父子关系"></a>Vue组件之间的父子关系</h4><p>实例：demo-1项目  ，打开一个项目要先npm install 来安装包</p>
<p>之中有三个组件  <strong>App.vue组件     Left组件     Right组件</strong>   彼此之间相互独立</p>
<p>然后我们在App.vue里面使用Left组件和Right组件，形成嵌套(形成父子关系 )</p>
<h4 id="Vue使用组件"><a href="#Vue使用组件" class="headerlink" title="Vue使用组件"></a>Vue使用组件</h4><p>vue使用组件的三个步骤：（在父组件中使用子组件）</p>
<ol>
<li>使用import语法导入需要的组件：import Left from ‘@/components/Left.vue’</li>
<li>使用components 节点注册组件：export default {  } 中的 components：{ Left } 节点</li>
<li>以标签的形式使用刚才注册的组件 <Left></Left></li>
</ol>
<p><strong>通过components注册的私有子组件</strong></p>
<p>例如：在组件A中components节点下，注册组件F,</p>
<p>则组件F只能用在组件A中，不能被用在组件C中</p>
<h4 id="Vue全局组件"><a href="#Vue全局组件" class="headerlink" title="Vue全局组件"></a>Vue全局组件</h4><p>在vue项目的main.js入口文件中，通过  vue.component()  方法，可以注册全局组件，示例代码如下</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入需要全局注册的组件</span></span><br><span class="line"><span class="keyword">import</span> Count <span class="keyword">from</span> <span class="string">&#x27;@/components/Count.vue&#x27;</span></span><br><span class="line"><span class="comment">// 参数1：字符串格式，表示组件的注册名称</span></span><br><span class="line"><span class="comment">// 参数2：需要被注册的组件</span></span><br><span class="line">Vue.components(<span class="string">&#x27;MyCount&#x27;</span>,Count)</span><br></pre></td></tr></table></figure>

<h4 id="组件的props"><a href="#组件的props" class="headerlink" title="组件的props"></a>组件的props</h4><p>小技巧：只有一行代码的方法可以简写</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;button @click=&quot;count += 1&quot;&gt;+1&lt;/button&gt;</span><br></pre></td></tr></table></figure>

<p>需求，希望两个组件count默认值在页面中不一样</p>
<p>props是组件的自定义属性，在封装通用插件时，合理的是使用props可以极大的提高组件的复用性</p>
<p>语法格式</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="attr">props</span>: [ <span class="string">&#x27;自定义属性A&#x27;</span>, <span class="string">&#x27;自定义属性B&#x27;</span>, <span class="string">&#x27;其他自定义属性...&#x27;</span> ],</span><br><span class="line">    </span><br><span class="line">    组件的私有数据</span><br><span class="line">    <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123; &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在Count.vue组件中使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;p&gt;Count组件的值是:双大括号 init 双大括号&lt;/p&gt;</span><br><span class="line">&lt;!-- 只有一行的方法可以简写 --&gt;</span><br><span class="line">&lt;button @click=&quot;init += 1&quot;&gt;+1&lt;/button&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  // props是自定义属性,允许使用者通过自定义属性，为当前组件指定初始值</span><br><span class="line">  props: [&#x27;init&#x27;],</span><br></pre></td></tr></table></figure>

<p>默认传递的是字符串类型，传递数字类型则</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;MyCount :init=&quot;6&quot;&gt;&lt;/MyCount&gt;</span><br></pre></td></tr></table></figure>

<p>问题：点击+1按钮虽然加1了，但是每一次点击控制台都会报错</p>
<p>因为在vue中<strong>props是只读的</strong>，直接修改props的值会报错</p>
<p>正确使用方法：把props的值赋值到data中给count，在页面上直接使用count</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="comment">// props是自定义属性,允许使用者通过自定义属性，为当前组件指定初始值</span></span><br><span class="line">  <span class="comment">// props中的数据可以直接在模板结构中被使用</span></span><br><span class="line">  <span class="attr">props</span>: [<span class="string">&#x27;init&#x27;</span>],</span><br><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">count</span>: <span class="built_in">this</span>.init</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>问题：如果用户在使用Count.vue的时候没有传递init怎么办呢,如:<MyCount></MyCount>，会出现页面没有数据的情况</p>
<h4 id="props的default默认值"><a href="#props的default默认值" class="headerlink" title="props的default默认值"></a>props的default默认值</h4><p>在声明自定义属性的时候，可以通过default来定义属性的默认值，示例代码如下  ( <strong>定义成对象格式的数据</strong> )</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">props: &#123;</span><br><span class="line">	<span class="attr">init</span>: &#123;</span><br><span class="line">		<span class="attr">default</span>: <span class="number">0</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<h4 id="props的type类型"><a href="#props的type类型" class="headerlink" title="props的type类型"></a>props的type类型</h4><p>我们之前使用  :init=”9” 来指定传过来的数据是number类型 ，去掉 ： 号，使用type选项来指定类型</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">props: &#123;</span><br><span class="line">  <span class="attr">init</span>: &#123;</span><br><span class="line">    <span class="attr">default</span>: <span class="number">0</span>,</span><br><span class="line">    <span class="comment">// 使用type指定数据类型，如果传递过来值不符合会报错</span></span><br><span class="line">    <span class="attr">type</span>: <span class="built_in">Number</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<h4 id="props的required必填项"><a href="#props的required必填项" class="headerlink" title="props的required必填项"></a>props的required必填项</h4><p>规定只要使用组件，就必须传递所需要的值</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">props: &#123;</span><br><span class="line">  <span class="attr">init</span>: &#123;</span><br><span class="line">    <span class="attr">default</span>: <span class="number">0</span>,</span><br><span class="line">    <span class="comment">// 使用type指定数据类型，如果传递过来值不符合会报错</span></span><br><span class="line">    <span class="attr">type</span>: <span class="built_in">Number</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<h4 id="组件之间的样式冲突问题"><a href="#组件之间的样式冲突问题" class="headerlink" title="组件之间的样式冲突问题"></a>组件之间的样式冲突问题</h4><p>默认情况下，写在.vue中的组件样式会全局生效，因此很容易在多个组件之间发生样式冲突问题</p>
<p>导致组件之间样式冲突的根本原因是：</p>
<ul>
<li>单页面应用程序中，所有的组件都是DOM结构，都是基于唯一的index.html页面来呈现的</li>
<li>每个组件中的样式，都会影响整个index.html页面中的DOM元素</li>
</ul>
<p>解决方案：</p>
<p>在style标签上加上范围</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br></pre></td></tr></table></figure>

<p><strong>其实scoped的原理就是</strong></p>
<p>单独在组件中的标签加上单独的自定义属性 如：  data-v-Left</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;left-container&quot; data-v-Left&gt;</span><br><span class="line">    &lt;h3 data-v-Left&gt;Left 组件&lt;/h3&gt;</span><br><span class="line">    &lt;hr data-v-Left/&gt;</span><br><span class="line">    &lt;MyCount init=&quot;9&quot; data-v-Left&gt;&lt;/MyCount&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;style&gt;</span><br><span class="line">h3[data-v-Left] &#123;</span><br><span class="line">  color: red;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>style加上scoped后，查看源码可以发现每个标签都加上了类似的属性</p>
<p>需求：希望修改Left组件里的Count组件标题改为粉色 ( 单独修改，Right组件中所有样式(包括Count组件)保持不变 )</p>
<p>思路是修改Left.vue组件里面的Count.vue组件的h5标签的样式，如果我们在Left.vue组件里面修改样式，Count组件的h5不会生效</p>
<p><strong>因为加了scoped后，h5标签也是有自定义属性的，但是Count.vue组件中没有自定义属性</strong></p>
<p>解决方法：在Left.vue中添加样式</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 当使用第三方组件库的时候，如果有修改第三方组件默认样式的需求，需要用到 /deep/</span><br><span class="line">/deep/ <span class="selector-tag">h5</span> &#123;</span><br><span class="line">  <span class="attribute">color</span>: pink;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这样，我们审查元素发现Count.vue中的h5标签的css 中，样式也加上了自定义属性，并且h5的父元素也有自定义属性了</p>
<h4 id="第三方插件的样式处理"><a href="#第三方插件的样式处理" class="headerlink" title="第三方插件的样式处理"></a>第三方插件的样式处理</h4><p>所以：当使用第三方组件库的时候，如果有修改第三方组件默认样式的需求，需要用到 /deep/</p>
<h3 id="vue文件的运行原理"><a href="#vue文件的运行原理" class="headerlink" title="vue文件的运行原理"></a>vue文件的运行原理</h3><p>.vue后缀结尾的文件在浏览器中不能直接被编译成页面，其实是通过vue-template-compiler这个插件来编译成html元素再渲染到页面上的</p>
<p>其实编写.vue组件就相当于一个实例，在页面上使用这个组件就相当于，new一个实例</p>
<h3 id="组件的生命周期"><a href="#组件的生命周期" class="headerlink" title="组件的生命周期"></a>组件的生命周期</h3><p>1.生命周期&amp;生命周期函数</p>
<p><strong>生命周期</strong>(Lift Cycle)是指一个组件从创建 -&gt; 运行 -&gt; 销毁的整个过程，强调的是一个时间段</p>
<p>某些时候有各种各样的需求，比如创建组件时要做某些操作，销毁组件时要做某些操作</p>
<p><strong>生命周期函数</strong>：是由vue框架提供的内置函数，会伴随着组件的生命周期，自动按次序执行。</p>
<p><strong>组件生命周期的第一个阶段</strong></p>
<p>组件创建阶段：</p>
<p> new Vue()  -&gt; beforeCreate(刚创建的时候) -&gt; created(刚创建好的时候) -&gt; beforeMount(在渲染之前) </p>
<p>​                    -&gt; mounted(已经成功被渲染到浏览器里了)</p>
<p><strong>组件生命周期的第二个阶段</strong></p>
<p>组件运行阶段：</p>
<p>​                  -&gt;beforeUpdate(在更新之前)  -&gt;  updated(组件更新完成时)</p>
<p><strong>组件生命周期的第三个阶段</strong></p>
<p>组件销毁阶段</p>
<p>​                  -&gt;beforeDestory(在销毁之前) -&gt; destoryed(组件销毁)</p>
<p>生命周期图示</p>
<img src="https://s4.ax1x.com/2022/01/07/79Fea9.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/07/79Fea9.png" srcset="" style="zoom: 50%;" />

<p>代码：基于Test.vue组件分析了运行过程</p>
<h4 id="组件的生命周期函数"><a href="#组件的生命周期函数" class="headerlink" title="组件的生命周期函数"></a>组件的生命周期函数</h4><h5 id="组件创建阶段"><a href="#组件创建阶段" class="headerlink" title="组件创建阶段"></a>组件创建阶段</h5><p><strong>beforeCreate函数</strong>不可用props/data/methods，测试代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">props</span>: [<span class="string">&#x27;info&#x27;</span>],</span><br><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">message</span>: <span class="string">&#x27;hello vue.js&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="function"><span class="title">show</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">&#x27;调用了Test组件的show方法&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 创建阶段的第一个生命周期函数</span></span><br><span class="line">  <span class="function"><span class="title">beforeCreate</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">this</span>.info)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">this</span>.message)</span><br><span class="line">    <span class="built_in">this</span>.show()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>报错，不能访问到这些数据</p>
<p><strong>created函数</strong>可以使用这些数据了,但是组件的模板结构未生成 用法：<strong>一般开发中在这个阶段向后端发起请求</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">created</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">this</span>.info)</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">this</span>.message)</span><br><span class="line">  <span class="built_in">this</span>.show()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>经常用于发起请求 </p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">&lt;h3&gt;共有双大括号 books.length 双大括号本图书&lt;/h3&gt;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">props</span>: [<span class="string">&#x27;info&#x27;</span>],</span><br><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">message</span>: <span class="string">&#x27;hello vue.js&#x27;</span>,</span><br><span class="line">      <span class="comment">//定义数组来存储图书，默认为空数组</span></span><br><span class="line">      <span class="attr">books</span>: []</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="function"><span class="title">show</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">&#x27;调用了Test组件的show方法&#x27;</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// 使用ajax发起请求，这里使用了原生语法</span></span><br><span class="line">    <span class="function"><span class="title">initBookList</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> xhr = <span class="keyword">new</span> XMLHttpRequest()</span><br><span class="line">      <span class="comment">// 这里后面用function会让里面的this有问题</span></span><br><span class="line">      xhr.addEventListener(<span class="string">&#x27;load&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">const</span> result = <span class="built_in">JSON</span>.parse(xhr.responseText)</span><br><span class="line">        <span class="built_in">console</span>.log(result)</span><br><span class="line">        <span class="built_in">this</span>.books = result.data</span><br><span class="line">      &#125;)</span><br><span class="line">      xhr.open(<span class="string">&#x27;GET&#x27;</span>,<span class="string">&#x27;http://www.liulongbin.top:3006/api/getbooks&#x27;</span>)</span><br><span class="line">      xhr.send()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 创建阶段的第一个生命周期函数</span></span><br><span class="line">  <span class="function"><span class="title">beforeCreate</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="function"><span class="title">created</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.initBookList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在之前组件的DOM结构还没有被创建，所以操作DOM的操作都做不了</p>
<p>通过一系列判断之后，基于<strong>数据</strong>和<strong>模板</strong>在内存中编译生成了HTML结构</p>
<p><strong>beforeMount函数</strong>，将要把内存中编译好的HTML结构渲染到浏览器中，此时浏览器中还没有当前组件的DOM结构</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;h3 id=<span class="string">&quot;mhy3&quot;</span>&gt;共有双大括号 books.length 双大括号本图书&lt;/h3&gt;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">beforeMount</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;beforeMount&#x27;</span>)</span><br><span class="line">    <span class="keyword">const</span> dom = <span class="built_in">document</span>.querySelector(<span class="string">&#x27;#mhy3&#x27;</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(dom)</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>



<p>当beforeMount执行完后，紧接着就是 用内存中编译生成的HTM结构，替换掉el属性指定的DOM元素</p>
<p>经过上面的步骤DOM结构就被渲染完了，可以执行操作DOM的操作了</p>
<p><strong>mounted函数</strong>，已经把内存中的HTML结构，成功渲染到浏览器中，此时浏览器中已然包含了当前组件的全部DOM结构</p>
<p>所以要操作DOM,最早在mounted阶段执行</p>
<h5 id="组件运行阶段"><a href="#组件运行阶段" class="headerlink" title="组件运行阶段"></a>组件运行阶段</h5><p><strong>beforeUpdate函数</strong>，将要根据变化过后，最新的数据，<strong>重新渲染</strong>组件的模板结构  （<strong>when data changes才会触发</strong>）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;p&gt;message的值是双大括号 message 双大括号&lt;/p&gt;</span><br><span class="line">&lt;button @click=&quot; message += &#x27;~&#x27; &quot;&gt;修改message的值&lt;/button&gt;</span><br><span class="line">  beforeUpdate() &#123;</span><br><span class="line">    console.log(&#x27;data的值改变了&#x27;)</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>执行到beforeUpdate的时候，<strong>data中的数据是最新的，但是页面中的元素还不是最新的</strong>，还没来得及渲染上去</p>
<p>Virtual DOM re-render and patch 这时候根据最新的数据，重新渲染组件的DOM结构</p>
<p>接下来会执行</p>
<p><strong>updated函数</strong>, 已经根据最新的数据完成了组件DOM结构的重新渲染。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">updated</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;updated&#x27;</span>)</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="built_in">this</span>.message)</span><br><span class="line">  <span class="keyword">const</span> dom = <span class="built_in">document</span>.querySelector(<span class="string">&#x27;#p1&#x27;</span>)</span><br><span class="line">  <span class="built_in">console</span>.log(dom.innerHTML)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>会打印出最新的data和最新的DOM元素</p>
<p>以上两个函数，最少执行0次，最多执行N次</p>
<h5 id="组件销毁阶段"><a href="#组件销毁阶段" class="headerlink" title="组件销毁阶段"></a>组件销毁阶段</h5><p>有一个v-if指令，当不需要时会动态销毁元素</p>
<p><strong>beforeDestory函数</strong>，将要销毁此组件，此时尚未销毁，组件还处在正常工作状态</p>
<p>下一个流程就是：销毁当前组件的数据监听器，子组件，事件监听</p>
<p><strong>destoryed函数</strong>，此组件已经被销毁，此组件在浏览器中对应的DOM结构已经完全被移除</p>
<h4 id="组件之间的关系"><a href="#组件之间的关系" class="headerlink" title="组件之间的关系"></a>组件之间的关系</h4><h5 id="1-组件之间的关系"><a href="#1-组件之间的关系" class="headerlink" title="1.组件之间的关系"></a>1.组件之间的关系</h5><p>在项目开发中，组件之间最常见的关系分别如下两种： </p>
<ol>
<li>父子关系</li>
<li>兄弟关系</li>
</ol>
<h5 id="2-父子组件之间的数据共享"><a href="#2-父子组件之间的数据共享" class="headerlink" title="2.父子组件之间的数据共享"></a>2.父子组件之间的数据共享</h5><p>父子之间数据共享分为 <strong>父组件向子组件传数据</strong>   和   <strong>子组件向父组件传数据</strong></p>
<h5 id="2-1-父组件向子组件传数据"><a href="#2-1-父组件向子组件传数据" class="headerlink" title="2.1.父组件向子组件传数据"></a>2.1.父组件向子组件传数据</h5><p>父组件向子组件传数据需要使用<strong>自定义属性</strong>，实例代码如下</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 父组件</span></span><br><span class="line"></span><br><span class="line">&lt;Son :msg=<span class="string">&quot;messgae&quot;</span> :user=<span class="string">&quot;userinfo&quot;</span>&gt;&lt;/Son&gt;</span><br><span class="line"><span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	<span class="keyword">return</span> &#123;</span><br><span class="line">		<span class="attr">message</span>: <span class="string">&#x27;hello vue.js&#x27;</span>,</span><br><span class="line">		<span class="attr">userinfo</span>: &#123; <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">	&lt;div&gt;</span><br><span class="line">        &lt;h5&gt;Son 组件&lt;/h5&gt;</span><br><span class="line">        &lt;p&gt;父组件传递过来的 msg 值是:双大括号 msg 双大括号&lt;/p&gt;</span><br><span class="line">        &lt;p&gt;父组件传递过来的 user 值是:双大括号 user 双大括号&lt;/p&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">props: [&#x27;msg&#x27;,&#x27;user&#x27;]</span><br></pre></td></tr></table></figure>

<p>注意：</p>
<p>简单类型是直接复制一份，引用类型(对象)是直接传递了引用</p>
<p>直接在子组件里修改引用类型的数据(对象),父组件中的原值不会改变，改变了值后指向一个新对象</p>
<p><strong>（如果直接修改对象里的值比如user.name，就可以改变了，但是不建议修改）</strong></p>
<h5 id="2-2-子组件向父组件传数据"><a href="#2-2-子组件向父组件传数据" class="headerlink" title="2.2.子组件向父组件传数据"></a>2.2.子组件向父组件传数据</h5><p>首先子组件要定义数据</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;h3&gt;双大括号 count 双大括号&lt;/h3&gt;</span><br><span class="line">&lt;button @click=&quot;add&quot;&gt;+1&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 子组件数据，传递到父组件</span><br><span class="line">      count: 0</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    add() &#123;</span><br><span class="line">      this.count += 1</span><br><span class="line">      // 修改数据时，通过$emit()触发自定义事件，修改父组件的值</span><br><span class="line">      this.$emit(&#x27;numchange&#x27;, this.count)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>父组件接收</p>
<p>子组件向父组件共享数据使用<strong>自定义事件</strong>，示例代码如下</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;Right @numchange=&quot;getNewCount&quot;&gt;&lt;/Right&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // val 接收的值是子组件里$emit传递的值</span><br><span class="line">    getNewCount(val) &#123;</span><br><span class="line">      this.countFromSon = val</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h5 id="3-兄弟组件之间传递值"><a href="#3-兄弟组件之间传递值" class="headerlink" title="3.兄弟组件之间传递值"></a>3.兄弟组件之间传递值</h5><p>在vue2.x中，兄弟组件之间数据共享的方案是<strong>EventBus</strong> </p>
<p>比如：兄弟组件A是发送放   ，兄弟组件B是接收方，两方首先都要定义一个数据</p>
<p>双方之间通过一个eventBus.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//向外共享Vue的实例对象</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vue()</span><br></pre></td></tr></table></figure>

<p>兄弟组件A(数据发送方)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">import bus from &#x27;./eventBus.js&#x27;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      msg: &#x27;hello vue.js&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">      sendMsg() &#123;</span><br><span class="line">          bus.$emit(&#x27;share&#x27;, this.msg)</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>兄弟组件B(接收方)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">import bus from &#x27;./eventBus.js&#x27;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 子组件数据，传递到父组件</span><br><span class="line">      count: 0,</span><br><span class="line">      // 兄弟Left组件传递过来的数据</span><br><span class="line">      msgFromLeft: &#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">      // 注意箭头函数</span><br><span class="line">      bus.$on(&#x27;share&#x27;, val =&gt; &#123;</span><br><span class="line">          this.msgFromLeft = val</span><br><span class="line">      &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>流程就是：</p>
<ul>
<li>创建eventBus.js模块，并向外共享一个Vue实例对象</li>
<li>在数据发送方，调用bus.$emit(‘事件名称’, 要发送的数据) 方法触发自定义事件</li>
<li>在数据的接收方，调用bus.$emit(‘事件名称’, 事件处理函数) 方法注册一个自定义事件</li>
</ul>
<h3 id="使用ref引用DOM元素"><a href="#使用ref引用DOM元素" class="headerlink" title="使用ref引用DOM元素"></a>使用ref引用DOM元素</h3><p>假设在vue中需要操作DOM，但是不建议使用JQuery</p>
<p>ref用来辅助开发者在不依赖jquery的情况下，获取DOM元素或组件的引用。</p>
<p>每个vue的组件实例上，都包含一个$ref对象，里面存储着对应DOM元素或组件的引用。默认情况下组件的$ref指向一个空对象</p>
<p>使用方法，在DOM元素标签上加上ref属性</p>
<p>第一步:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;h1 ref=&quot;myh1&quot;&gt;App 根组件&lt;/h1&gt;</span><br><span class="line">&lt;button @click=&quot;showThis&quot;&gt;打印&lt;/button&gt;</span><br></pre></td></tr></table></figure>

<p>第二步: 通过  this.$ref 去拿到DOM元素</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">methods: &#123;</span><br><span class="line">	<span class="function"><span class="title">showThis</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="comment">// 当前组件的实例对象</span></span><br><span class="line">      <span class="comment">// console.log(this.$refs.myh1)</span></span><br><span class="line">      <span class="built_in">this</span>.$refs.myh1.style.color = <span class="string">&#x27;red&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="ref引用组件实例"><a href="#ref引用组件实例" class="headerlink" title="ref引用组件实例"></a>ref引用组件实例</h3><p>如果想使用ref引用页面上的组件实例，代码如下：</p>
<p>想在父组件设置一个按钮清空子组件Left的值，获取子组件实例，然后通过  <strong>$ref</strong>  调用子组件实例里面的方法</p>
<p>App.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;Left ref=&quot;comLeft&quot;&gt;&lt;/Left&gt;</span><br><span class="line">&lt;button @click=&quot;onReset&quot;&gt;重制Left的count值为0&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">    methods: &#123;</span><br><span class="line">    	// 点击按钮重制Left组件的count值</span><br><span class="line">    	onReset() &#123;</span><br><span class="line">      		this.$refs.comLeft.reset()</span><br><span class="line">            // 或者也可以直接操作data值</span><br><span class="line">            this.$refs.comLeft.count = 0</span><br><span class="line">    	&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>Left.vue中定义了reset方法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&lt;h3&gt;count值是:双大括号 count 双大括号&lt;/h3&gt;</span><br><span class="line">&lt;button @click=&quot;reset&quot;&gt;重置count&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">    data() &#123;</span><br><span class="line">    	return &#123;</span><br><span class="line">      		count: 0</span><br><span class="line">    	&#125;</span><br><span class="line">  	&#125;,</span><br><span class="line">	methods: &#123;</span><br><span class="line">    	reset() &#123;</span><br><span class="line">      		this.count = 0</span><br><span class="line">    	&#125;</span><br><span class="line">  	&#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h4 id="实现按钮控制输入框的显示"><a href="#实现按钮控制输入框的显示" class="headerlink" title="实现按钮控制输入框的显示"></a>实现按钮控制输入框的显示</h4><p>思路：</p>
<ul>
<li>按钮切换 v-if 属性的值来显示输入框，并隐藏按钮</li>
<li>@blur 当输入框失去焦点的时候，隐藏输入框并显示按钮</li>
<li>显示输入框时没有焦点，要使输入框一显示就获取到焦点 （用到了ref引用了）</li>
</ul>
<p>一般是在showInput()方法内写：<strong>this.$refs.iptRef.focus()</strong>   但是报错了  focus is undefined</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;text&quot; v-if=&quot;inputVisible&quot; @blur=&quot;showButton&quot;/&gt;</span><br><span class="line">&lt;button @click=&quot;showInput&quot; v-else&gt;展示输入框&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      inputVisible: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">  	showInput() &#123;</span><br><span class="line">      // 1.展示出文本框</span><br><span class="line">      this.inputVisible = true</span><br><span class="line">      // 2.让文本框自动获得焦点</span><br><span class="line">      this.$refs.iptRef.focus()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>打印信息查看:  console.log(this.$refs.iptRef)     控制台打印了：    undefined</p>
<p><strong>这时候发现：由于生命周期，按钮点下去的时候DOM元素还没出现，所以拿不到元素</strong><br>解决办法：想办法让这个方法延迟到等页面加载完全后</p>
<p>vue提供了</p>
<h4 id="this-nextTick-cb-方法"><a href="#this-nextTick-cb-方法" class="headerlink" title="this.$nextTick(cb)方法"></a>this.$nextTick(cb)方法</h4><p>cb是回调函数 call back，写成箭头函数形式</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">showInput</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="comment">// 1.展示出文本框</span></span><br><span class="line">  <span class="built_in">this</span>.inputVisible = <span class="literal">true</span></span><br><span class="line">  <span class="comment">// 2.让文本框自动获得焦点</span></span><br><span class="line">  <span class="comment">// this.$refs.iptRef.focus()</span></span><br><span class="line">  <span class="built_in">this</span>.$nextTick(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.$refs.iptRef.focus()</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>



<h3 id="购物车案例"><a href="#购物车案例" class="headerlink" title="购物车案例"></a>购物车案例</h3><h4 id="数组的some方法"><a href="#数组的some方法" class="headerlink" title="数组的some方法"></a>数组的some方法</h4><p>通常的循环找元素：forEach()方法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arr = [<span class="string">&#x27;小红&#x27;</span>,<span class="string">&#x27;小白&#x27;</span>,<span class="string">&#x27;小黑&#x27;</span>,<span class="string">&#x27;小蓝&#x27;</span>]</span><br><span class="line">arr.forEach(<span class="function">(<span class="params">item,index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span>(item === <span class="string">&#x27;小蓝&#x27;</span>) &#123;</span><br><span class="line">	<span class="built_in">console</span>.log(index)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>forEach找到元素后，并不会停止循环，性能较低</p>
<p>some()方法：找到指定项后可以通过return true终止循环</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">arr.some(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">	<span class="keyword">if</span>(item === <span class="string">&#x27;小黑&#x27;</span>) &#123;</span><br><span class="line">     	<span class="built_in">console</span>.log(item,index)</span><br><span class="line">        <span class="comment">// 找到指定项后可以通过return true终止循环</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h4 id="数组的every方法"><a href="#数组的every方法" class="headerlink" title="数组的every方法"></a>数组的every方法</h4><p>判断数组中的state值，是否全为true   用途：可以用在判断购物车的商品是否全部被选中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arr = [</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">1</span>,<span class="attr">name</span>: <span class="string">&#x27;西瓜&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">2</span>,<span class="attr">name</span>: <span class="string">&#x27;榴莲&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">3</span>,<span class="attr">name</span>: <span class="string">&#x27;草莓&#x27;</span>, <span class="attr">state</span>: <span class="literal">false</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">4</span>,<span class="attr">name</span>: <span class="string">&#x27;哈密瓜&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">]</span><br><span class="line"><span class="comment">// 判断水果数组是否被全选了,是否全部都是 true</span></span><br><span class="line"><span class="keyword">const</span> result = arr.every(<span class="function"><span class="params">item</span> =&gt;</span> item.state)</span><br><span class="line"><span class="built_in">console</span>.log(result)</span><br><span class="line"><span class="comment">// 全部是是true，会输出true，有一项不是true，就会输出false</span></span><br></pre></td></tr></table></figure>

<h4 id="数组的reduce方法"><a href="#数组的reduce方法" class="headerlink" title="数组的reduce方法"></a>数组的reduce方法</h4><p>需求：把购物车中选中的物品的价格总数计算出来</p>
<p>普通实现方式</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="keyword">const</span> arr = [</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">1</span>,<span class="attr">name</span>: <span class="string">&#x27;西瓜&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span>, <span class="attr">price</span>: <span class="number">10</span>, <span class="attr">count</span>: <span class="number">1</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">2</span>,<span class="attr">name</span>: <span class="string">&#x27;榴莲&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span>, <span class="attr">price</span>: <span class="number">80</span>, <span class="attr">count</span>: <span class="number">1</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">3</span>,<span class="attr">name</span>: <span class="string">&#x27;草莓&#x27;</span>, <span class="attr">state</span>: <span class="literal">false</span>, <span class="attr">price</span>: <span class="number">40</span>, <span class="attr">count</span>: <span class="number">2</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">4</span>,<span class="attr">name</span>: <span class="string">&#x27;苹果&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span>, <span class="attr">price</span>: <span class="number">20</span>, <span class="attr">count</span>: <span class="number">1</span> &#125;</span><br><span class="line">]</span><br><span class="line"><span class="comment">// 把购物车数组中勾选的总价累计加起来</span></span><br><span class="line"><span class="comment">// fileter先过滤出来了选中的项,forEach循环每一项，价格和数量相乘然后累加到amt上</span></span><br><span class="line"><span class="keyword">let</span> amt = <span class="number">0</span>  <span class="comment">// 总价格</span></span><br><span class="line">arr.filter(<span class="function"><span class="params">item</span> =&gt;</span> item.state).forEach(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">    amt += item.price * item.count</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;水果的总价为:&#x27;</span>,amt)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>reduce()就是一个累加器</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="keyword">const</span> arr = [</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">1</span>,<span class="attr">name</span>: <span class="string">&#x27;西瓜&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span>, <span class="attr">price</span>: <span class="number">10</span>, <span class="attr">count</span>: <span class="number">1</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">2</span>,<span class="attr">name</span>: <span class="string">&#x27;榴莲&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span>, <span class="attr">price</span>: <span class="number">80</span>, <span class="attr">count</span>: <span class="number">1</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">3</span>,<span class="attr">name</span>: <span class="string">&#x27;草莓&#x27;</span>, <span class="attr">state</span>: <span class="literal">false</span>, <span class="attr">price</span>: <span class="number">40</span>, <span class="attr">count</span>: <span class="number">2</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">4</span>,<span class="attr">name</span>: <span class="string">&#x27;苹果&#x27;</span>, <span class="attr">state</span>: <span class="literal">true</span>, <span class="attr">price</span>: <span class="number">20</span>, <span class="attr">count</span>: <span class="number">1</span> &#125;</span><br><span class="line">]</span><br><span class="line"><span class="comment">// 把购物车数组中勾选的总价累计加起来</span></span><br><span class="line"><span class="comment">// fileter先过滤出来了选中的项,</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// arr.filter(item =&gt; item.state).reduce((累加的结果,当前循环项) =&gt; &#123; &#125;, 初始值amt)</span></span><br><span class="line"><span class="comment">// return amt 就是每一次循环结束，会都去更新amt的值，这样下一次循环就是上一次循环累加后的值了</span></span><br><span class="line"><span class="keyword">const</span> result = arr.filter(<span class="function"><span class="params">item</span> =&gt;</span> item.state).reduce(<span class="function">(<span class="params">amt, item</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> amt += item.price * item.count</span><br><span class="line">&#125;, <span class="number">0</span>)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;水果的总价为:&#x27;</span>,result)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>reduce的简化写法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> result = arr.filter(<span class="function"><span class="params">item</span> =&gt;</span> item.state).reduce(<span class="function">(<span class="params">amt, item</span>) =&gt;</span> amt += item.price * item.count, <span class="number">0</span>)</span><br></pre></td></tr></table></figure>

<h4 id="购物车案例实现步骤"><a href="#购物车案例实现步骤" class="headerlink" title="购物车案例实现步骤"></a>购物车案例实现步骤</h4><ul>
<li>初始化项目基本结构，npm install -&gt;  npm run serve</li>
<li>注册并使用Header组件</li>
<li>基于axios请求商品列表数据，循环渲染购物车商品结构</li>
</ul>
<p>运行命令先安装axios</p>
<figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i axios <span class="literal">-S</span></span><br></pre></td></tr></table></figure>

<p>在App.vue中发请求拿到购物车的列表数据</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"><span class="comment">// 1.导入需要的组件</span></span><br><span class="line"><span class="keyword">import</span> Header <span class="keyword">from</span> <span class="string">&quot;@/components/Header/Header&quot;</span>;</span><br><span class="line"><span class="comment">// 导入axios</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">components</span>: &#123;</span><br><span class="line">    Header</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="comment">// 封装请求列表数据的方法</span></span><br><span class="line">    <span class="keyword">async</span> <span class="function"><span class="title">initCartList</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="comment">// 调用axios的get方法，请求列表数据</span></span><br><span class="line">      <span class="comment">// 解构赋值</span></span><br><span class="line">      <span class="keyword">const</span> &#123;<span class="attr">data</span>:res&#125; = <span class="keyword">await</span> axios.get(<span class="string">&#x27;https://www.escook.cn/api/cart&#x27;</span>)</span><br><span class="line">      <span class="built_in">console</span>.log(res)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 生命周期函数中调用请求函数</span></span><br><span class="line">  <span class="function"><span class="title">created</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="comment">// 调用请求数据的方法</span></span><br><span class="line">    <span class="built_in">this</span>.initCartList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>请求回来的数据要用在页面上，必须转存到data中</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="comment">// 用来存放购物车数据</span></span><br><span class="line">      <span class="attr">list</span>: []</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">methods</span>: &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="function"><span class="title">initCartList</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> &#123;<span class="attr">data</span>:res&#125; = <span class="keyword">await</span> axios.get(<span class="string">&#x27;https://www.escook.cn/api/cart&#x27;</span>)</span><br><span class="line">      <span class="comment">// 请求回来的数据要用在页面上，必须转存到data中</span></span><br><span class="line">      <span class="keyword">if</span>(res.status === <span class="number">200</span>) &#123;  <span class="comment">//判断请求状态</span></span><br><span class="line">        <span class="built_in">this</span>.list = res.list</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h5 id="渲染Goods组件"><a href="#渲染Goods组件" class="headerlink" title="渲染Goods组件"></a>渲染Goods组件</h5><p>首先导入，然后使用标签，给标签加上v-for属性</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 循环渲染每一个商品的信息 --&gt;</span><br><span class="line">&lt;Goods v-for=&quot;item in list&quot; :key=&quot;item.id&quot;&gt;&lt;/Goods&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import Goods from &quot;@/components/Goods/Goods&quot;;</span><br><span class="line">export default &#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    Header,</span><br><span class="line">    Goods</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>渲染goods组件标题，在组件中使用props</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;h6 class=&quot;goods-title&quot;&gt;双大括号 title 双大括号&lt;/h6&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 要渲染的商品的标题</span><br><span class="line">    title: &#123;</span><br><span class="line">      default: &#x27;&#x27;,</span><br><span class="line">      type: String</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在使用Goods组件的时候，动态绑定值要加上 ‘  :  ‘ 不然，渲染出来是一个字符串</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Goods v-for=&quot;item in list&quot; :key=&quot;item.id&quot; :title=&quot;item.goods_name&quot;&gt;&lt;/Goods&gt;</span><br></pre></td></tr></table></figure>

<p>一个一个定义，然后在App.vue中使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;Goods</span><br><span class="line">    v-for=&quot;item in list&quot;</span><br><span class="line">    :key=&quot;item.id&quot;</span><br><span class="line">    :title=&quot;item.goods_name&quot;</span><br><span class="line">    :pic=&quot;item.goods_img&quot;</span><br><span class="line">    :price=&quot;item.goods_price&quot;</span><br><span class="line">    :state=&quot;item.goods_state&quot;</span><br><span class="line">&gt;</span><br><span class="line">&lt;/Goods&gt;</span><br></pre></td></tr></table></figure>

<h5 id="复选框操作更改对应数据项"><a href="#复选框操作更改对应数据项" class="headerlink" title="复选框操作更改对应数据项"></a>复选框操作更改对应数据项</h5><p>问题：勾选框修改，但是值没有变          原因：props的值是不可改变的，所以绑定属性用的是v-bind</p>
<p>解决办法：<strong>在Goods组件里，勾选或者不勾选，然后把值传过来，传到App.vue里面去修改遍历的list的状态值</strong> </p>
<p>（子向父传值：自定义事件）</p>
<p>思路：通过自定义事件，子组件把商品的id和状态传到父组件，修改数据的状态值</p>
<p><strong>子组件</strong></p>
<p>子组件中监听复选框状态变 化的事件，拿到最新的勾选状态&lt;input type=”checkbox” **@change**=”stateChange” /&gt;只要状态发生变化就会触发@change事件</p>
<p>当监听到勾选状态变化后，应该立即把最新的状态，通过自定义事件的形式this.$emit(‘state-change’,{id,状态})发送到父组件</p>
<p><strong>父组件</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;Goods @state-change=&quot;getNewState&quot;&gt;&lt;/Goods&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">methods: &#123;</span><br><span class="line">    // 事件对象e,就是通过this.$emit传递过来的值</span><br><span class="line">	getNewState(e) &#123;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>实现代码：Goods.vue  关键部分</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;cb1&quot; :checked=&quot;state&quot; @change=&quot;stateChange&quot;/&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 商品的id</span><br><span class="line">    id: &#123;</span><br><span class="line">      // 必须传递值</span><br><span class="line">      required: true,</span><br><span class="line">      type: Number</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 只要复选框状态发生变化就会调用处理函数，e是事件对象</span><br><span class="line">    stateChange(e) &#123;</span><br><span class="line">      // 打印e,里面的e.target.checked的值就是最新的复选框的值</span><br><span class="line">      const state = e.target.checked</span><br><span class="line">      // 触发自定义事件</span><br><span class="line">      this.$emit(&#x27;state-change&#x27;,&#123;id: this.id,value: state&#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>App.vue  代码    接收id和状态值，去数组中找数据并更改state项数据</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;Goods</span><br><span class="line">    v-for=&quot;item in list&quot;</span><br><span class="line">    :key=&quot;item.id&quot;</span><br><span class="line">    :id=&quot;item.id&quot;</span><br><span class="line">    :title=&quot;item.goods_name&quot;</span><br><span class="line">    :pic=&quot;item.goods_img&quot;</span><br><span class="line">    :price=&quot;item.goods_price&quot;</span><br><span class="line">    :state=&quot;item.goods_state&quot;</span><br><span class="line">    @state-change=&quot;getNewState&quot;</span><br><span class="line">&gt;</span><br><span class="line">&lt;/Goods&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 接收子组件传递过来的id和状态，更改每个对应数据的state值</span><br><span class="line">    getNewState(val) &#123;</span><br><span class="line">      console.log(val)    // &#123; id:id,value:state &#125;</span><br><span class="line">      this.list.some(item =&gt; &#123;</span><br><span class="line">        if (item.id === val.id) &#123;</span><br><span class="line">          item.goods_state = val.value</span><br><span class="line">          // 终止循环</span><br><span class="line">          return true</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>好了，功能实现了，但是。。。点击下面第三项的图片会修改第一项的复选框。。。和列表例子出现的问题一样</strong></p>
<h5 id="列表复选框的bug"><a href="#列表复选框的bug" class="headerlink" title="列表复选框的bug"></a>列表复选框的bug</h5><p>查看Goods组件发现</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 复选框 --&gt;</span><br><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;cb1&quot; :checked=&quot;state&quot; @change=&quot;stateChange&quot;/&gt;</span><br><span class="line">&lt;label class=&quot;custom-control-label&quot; for=&quot;cb1&quot;&gt;</span><br></pre></td></tr></table></figure>

<p>id和for都被写死了cb1,要动态生成才行</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 复选框 --&gt;</span><br><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; :id=&quot;&#x27;cb1&#x27;+id&quot; :checked=&quot;state&quot; @change=&quot;stateChange&quot;/&gt;</span><br><span class="line">&lt;label class=&quot;custom-control-label&quot; :for=&quot;&#x27;cb1&#x27;+id&quot;&gt;</span><br></pre></td></tr></table></figure>

<h5 id="结算付款组件Footer"><a href="#结算付款组件Footer" class="headerlink" title="结算付款组件Footer"></a>结算付款组件Footer</h5><p>导入使用组件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;Footer&gt;&lt;/Footer&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import Footer from &quot;@/components/Footer/Footer&quot;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>接下来，处理组件中全选选项和列表复选框的关联，要计算出全部选中的状态，使用<strong>计算属性</strong></p>
<p>根据列表里的每一件商品的状态计算出全选选项的布尔值</p>
<p><strong>在App.vue中定义计算属性来计算list的goods_state值</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">computed</span>: &#123;</span><br><span class="line">    <span class="comment">// 动态计算出全选框的状态是true还是false</span></span><br><span class="line">    <span class="function"><span class="title">fullState</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="comment">// 只要有一项为false就为false，全部为true才是true，使用数组的every方法</span></span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">this</span>.list.every(<span class="function"><span class="params">item</span> =&gt;</span> item.goods_state)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br></pre></td></tr></table></figure>

<p>父组件有值了，要传递到子组件Footer中去</p>
<p>父组件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Footer :isFull=&quot;fullState&quot;&gt;&lt;/Footer&gt;</span><br></pre></td></tr></table></figure>

<p>子组件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;cbFull&quot; :checked=&quot;isFull&quot; /&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 全选的状态</span><br><span class="line">    isFull: &#123;</span><br><span class="line">      default: false,</span><br><span class="line">      type: Boolean</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>要实现勾选全选框，全部Goods组件选上的操作，就要子组件Footer向父组件App.vue传值</p>
<p><strong>使用自定义事件</strong></p>
<p>首先子组件监听全选框的变化,使用 @change    子组件向父组件传值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;cbFull&quot; :checked=&quot;isFull&quot; @change=&quot;fullChange&quot;/&gt;</span><br></pre></td></tr></table></figure>

<p>子组件Footer</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=&quot;checkbox&quot; class=&quot;custom-control-input&quot; id=&quot;cbFull&quot; :checked=&quot;isFull&quot; @change=&quot;fullChange&quot;/&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 监听到了全选的状态变化,事件对象e</span><br><span class="line">    fullChange(e) &#123;</span><br><span class="line">      // 拿到了状态，传递到父组件App.vue里去修改所有的item的状态</span><br><span class="line">      this.$emit(&#x27;fullChange&#x27;,e.target.checked)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>父组件App</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;Footer :isFull=&quot;fullState&quot; @fullChange=&quot;getFullState&quot;&gt;&lt;/Footer&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 接收子组件Footer传递过来的全选按钮的状态</span><br><span class="line">    getFullState(val) &#123;</span><br><span class="line">        // forEach 遍历每一项</span><br><span class="line">      	this.list.forEach(item =&gt; (item.goods_state = val))</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>结算组件的价格和总数</p>
<p>实现思路：在App组件中计算出值（计算属性），再传递给子组件Footer</p>
<p><strong>在App.vue内</strong>，先定义计算属性，使用数组方法   1.使用filter方法   再    2.reduce累加</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">	<span class="function"><span class="title">amt</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">this</span>.list.filter(<span class="function"><span class="params">item</span> =&gt;</span> item.goods_state).reduce(<span class="function">(<span class="params">total,item</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> total += item.goods_price * item.goods_count</span><br><span class="line">      &#125;,<span class="number">0</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>reduce简写</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">amt</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="built_in">this</span>.list</span><br><span class="line">		.filter(<span class="function"><span class="params">item</span> =&gt;</span> item.goods_state)</span><br><span class="line">		.reduce(<span class="function">(<span class="params">total,item</span>) =&gt;</span> (total += item.goods_price * item.goods_count),<span class="number">0</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>子组件接收</strong>，定义一个props</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;span class=&quot;total-price&quot;&gt;￥双大括号 amount 双大括号&lt;/span&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 总价格</span><br><span class="line">    amount: &#123;</span><br><span class="line">      default: 0,</span><br><span class="line">      type: Number</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在父组件使用子组件时传参</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Footer :isFull=&quot;fullState&quot; :amount=&quot;amt&quot; @fullChange=&quot;getFullState&quot;&gt;&lt;/Footer&gt;</span><br></pre></td></tr></table></figure>

<p>需要两位小数，使用toFixed方法</p>
<p>Footer.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;span class=&quot;total-price&quot;&gt;￥双大括号 amount.toFixed(2) 双大括号&lt;/span&gt;</span><br></pre></td></tr></table></figure>

<p>这里标签内的顺序是先绑定指令，后绑定数据，最后绑定@事件</p>
<h5 id="在Goods组件中使用Count组件"><a href="#在Goods组件中使用Count组件" class="headerlink" title="在Goods组件中使用Count组件"></a>在Goods组件中使用Count组件</h5><p>继续先导入，在Goods.vue中标签使用组件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Counter&gt;&lt;/Counter&gt;</span><br></pre></td></tr></table></figure>

<p>业务中，要把数组中的数量这个值传递到Count组件中去</p>
<p>依旧是父组件传值，但是这里好像要传两次？</p>
<p>实现思路：离得比较远的组件之间通信可以使用eventBus传递数据，加减商品数量操作需要两个数据id和数量</p>
<p>首先在Footer组件中定义出来</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    id: &#123;</span><br><span class="line">      type: Number,</span><br><span class="line">      required: true</span><br><span class="line">    &#125;,</span><br><span class="line">    nums: &#123;</span><br><span class="line">      default: 1,</span><br><span class="line">      type: Number</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>Goods组件本来有id属性，那么使用Footer组件时传递过来就行了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Counter :nums=&quot;count&quot; :id=&quot;id&quot;&gt;&lt;/Counter&gt;</span><br></pre></td></tr></table></figure>

<p>下一步开始在Footer组件里面写点击加号增加数量的事件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;button type=&quot;button&quot; class=&quot;btn btn-light btn-sm&quot; @click=&quot;add&quot;&gt;+&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    add() &#123;</span><br><span class="line">      // 不用修改nums的值，直接发送数据就行 格式为&#123; id,value &#125;</span><br><span class="line">      // id为商品的id，数量为最新的购买数量</span><br><span class="line">      const obj = &#123; id:this.id,value: this.nums+1 &#125;</span><br><span class="line">      // 通过eventBus 发送给App.vue</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>接下来使用eventBus.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vue()</span><br></pre></td></tr></table></figure>

<p>首先导入eventBus  , 发送方Footer使用bus.$emit</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">add</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="comment">// 不用修改nums的值，直接发送数据就行 格式为&#123; id,value &#125;</span></span><br><span class="line">  <span class="comment">// id为商品的id，数量为最新的购买数量</span></span><br><span class="line">  <span class="keyword">const</span> obj = &#123; <span class="attr">id</span>:<span class="built_in">this</span>.id,<span class="attr">value</span>: <span class="built_in">this</span>.nums+<span class="number">1</span> &#125;</span><br><span class="line">  <span class="comment">// 通过eventBus 发送给App.vue</span></span><br><span class="line">  eventBus.$emit(<span class="string">&#x27;share&#x27;</span>,obj)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接收方App.vue</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">// 生命周期函数</span></span><br><span class="line"> <span class="function"><span class="title">created</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line"><span class="comment">// 接收footer传递过来的商品数量</span></span><br><span class="line">   eventBus.$on(<span class="string">&#x27;share&#x27;</span>,<span class="function"><span class="params">val</span> =&gt;</span> &#123;</span><br><span class="line">     <span class="built_in">this</span>.list.some(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">       <span class="keyword">if</span> (item.id === val.id) &#123;</span><br><span class="line">         item.goods_count = val.value</span><br><span class="line">         <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">       &#125;</span><br><span class="line">     &#125;)</span><br><span class="line">   &#125;)</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<p><strong>接下来是数量的累加和count组件减少的操作</strong></p>
<p>思路：在父组件中定义计算属性，计算出来传递到子组件中</p>
<p>App.vue中定义计算属性</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">    <span class="comment">// 已勾选商品的总数量，简写版</span></span><br><span class="line">    <span class="function"><span class="title">total</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">this</span>.list.filter(<span class="function"><span class="params">item</span> =&gt;</span> item.goods_state).reduce(<span class="function">(<span class="params">counts,item</span>) =&gt;</span> (counts += item.goods_count),<span class="number">0</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在Footer中定义props</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 已勾选的商品的总数量</span><br><span class="line">    allCount: &#123;</span><br><span class="line">      default: 0,</span><br><span class="line">      type: Number</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>App.vue使用的时候传值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Footer :isFull=&quot;fullState&quot; :amount=&quot;amt&quot; :all-count=&quot;total&quot; @fullChange=&quot;getFullState&quot;&gt;&lt;/Footer&gt;</span><br></pre></td></tr></table></figure>

<p>下面写<strong>减少商品数量</strong>的业务</p>
<p>Count.vue，一样的绑定事件,一样的方法，只是变成-1了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;button type=&quot;button&quot; class=&quot;btn btn-light btn-sm&quot; @click=&quot;sub&quot;&gt;-&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import eventBus from &quot;@/components/eventBus&quot;;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    sub() &#123;</span><br><span class="line">      const obj = &#123; id:this.id,value: this.nums-1 &#125;</span><br><span class="line">      // 通过eventBus 发送给App.vue</span><br><span class="line">      eventBus.$emit(&#x27;share&#x27;,obj)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>但是要判断一下等于0的时候不能变成负数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">sub</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="comment">// 判断为0时，跳出不执行后面</span></span><br><span class="line">	<span class="keyword">if</span> (<span class="built_in">this</span>.nums-<span class="number">1</span> === <span class="number">0</span>) <span class="keyword">return</span></span><br><span class="line">	<span class="keyword">const</span> obj = &#123; <span class="attr">id</span>:<span class="built_in">this</span>.id,<span class="attr">value</span>: <span class="built_in">this</span>.nums-<span class="number">1</span> &#125;</span><br><span class="line">     <span class="comment">// 通过eventBus 发送给App.vue</span></span><br><span class="line">     eventBus.$emit(<span class="string">&#x27;share&#x27;</span>,obj)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="动态组件"><a href="#动态组件" class="headerlink" title="动态组件"></a>动态组件</h3><ol>
<li>什么是动态组件</li>
</ol>
<p><strong>方便实现不同组件之间的按需展示，动态切换组件的显示隐藏</strong></p>
<ol>
<li>如何实现动态组件渲染</li>
</ol>
<p>vue提供了内置的<component>组件，专门用来实现动态组件的渲染，示例代码如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">data() &#123;</span><br><span class="line">	// 1.当前要渲染的组件名称</span><br><span class="line">	return &#123; comName: &#x27;Left&#x27;&#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;!-- 2.通过is属性，动态指定要渲染的组件 --&gt;</span><br><span class="line">&lt;component :is=&quot;comName&quot;&gt;&lt;/component&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 3.点击按钮，动态切换组件的名称 --&gt;</span><br><span class="line">&lt;button @click=&quot;comName = &#x27;Left&#x27;&quot;&gt;展示Left组件&lt;/button&gt;</span><br><span class="line">&lt;button @click=&quot;comName = &#x27;Right&#x27;&quot;&gt;展示Right组件&lt;/button&gt;</span><br></pre></td></tr></table></figure>

<p>正常写法：导入，注册，使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 渲染 Left 组件和 Right 组件 --&gt;</span><br><span class="line">&lt;Right&gt;&lt;/Right&gt;</span><br><span class="line">&lt;Left&gt;&lt;/Left&gt;</span><br></pre></td></tr></table></figure>

<p>用动态组件component</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;component is=&quot;Left&quot;&gt;&lt;/component&gt;</span><br><span class="line">&lt;component is=&quot;Right&quot;&gt;&lt;/component&gt;</span><br></pre></td></tr></table></figure>

<p>这样我们就可以动态去修改is的属性了</p>
<p>使用场景：比如tab栏</p>
<p>在页面上放两个按钮，点击展示Left和Right，添加方法修改comName的值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;button @click=&quot;comName = &#x27;Left&#x27;&quot;&gt;显示Left&lt;/button&gt;</span><br><span class="line">&lt;button @click=&quot;comName = &#x27;Right&#x27;&quot;&gt;显示Right&lt;/button&gt;</span><br></pre></td></tr></table></figure>

<p>需求场景：两个组件可以切换了，我们在页面中的数据切换时是没有保存的</p>
<p>比如：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;h3&gt;双大括号 count 双大括号&lt;/h3&gt;</span><br><span class="line">&lt;button @click=&quot;count += 1&quot;&gt;+1&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      count: 0</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>切换组件后，count数据重新清0，这是因为在切换组件的过程中，<strong>Left组件被创建和销毁，数据并不会保存下来</strong></p>
<p>那么我们得想办法不然组件销毁</p>
<h4 id="Keep-Alive的使用"><a href="#Keep-Alive的使用" class="headerlink" title="Keep-Alive的使用"></a>Keep-Alive的使用</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- keep-alive不然组件在切换的时候销毁 --&gt;</span><br><span class="line">&lt;keep-alive&gt;</span><br><span class="line">  &lt;component :is=&quot;comName&quot;&gt;&lt;/component&gt;</span><br><span class="line">&lt;/keep-alive&gt;</span><br></pre></td></tr></table></figure>

<p>原理：组件并没有被销毁，而是被<strong>缓存</strong>起来了，下一次还是这个组件</p>
<p>好了，我们实现了切换组件数据也保存下来了</p>
<p><strong>有需求：我们需要在切换组件的时候，让组件做一些业务逻辑的操作，keep-alive提供了生命周期函数</strong></p>
<p>keep-alive对应的生命周期函数</p>
<p>当组件被缓存时，会自动触发组件的deactivated生命周期函数</p>
<p>当组件被激活时，会自动触发组件的activated生命周期函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">deactivated</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;组件被缓存了&#x27;</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="title">activated</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;组件被激活了&#x27;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="keep-alive的include属性"><a href="#keep-alive的include属性" class="headerlink" title="keep-alive的include属性"></a>keep-alive的include属性</h4><p>默认情况下keep-alive会把包裹起来的所有组件都加上缓存，如果希望只缓存一个组件呢</p>
<p>include属性用来指定，只有名称匹配的组件才会被缓存。<strong>多个组件名之间用英文逗号分隔</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- keep-alive不然组件在切换的时候销毁,include属性可以指定只缓存某一个组件 --&gt;</span><br><span class="line">&lt;keep-alive include=&quot;Left&quot;&gt;</span><br><span class="line">  &lt;component :is=&quot;comName&quot;&gt;&lt;/component&gt;</span><br><span class="line">&lt;/keep-alive&gt;</span><br></pre></td></tr></table></figure>

<p><strong>exclude属性</strong>，排除组件，用法一样，两个属性只能用其中一个</p>
<p>知识点：我们如果没有给组件起名称，默认就是组件文件名的名称</p>
<p>比如Left.vue组件文件，导入的名称就是Left，使用的名称也是Left，我们也可以给组件设置一个另外的名称</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;MyRight&#x27;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>这样使用<Right></Right>的时候，打开vue调式工具发现组件名称变了</p>
<p>更改了组件的name属性后，发现include和exclude都失效了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;keep-alive exclude=&quot;Right&quot;&gt;</span><br></pre></td></tr></table></figure>

<p>MyLeft和MyRight都被缓存了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;keep-alive exclude=&quot;MyRight&quot;&gt;</span><br></pre></td></tr></table></figure>

<p>这就是名字不一样的问题了</p>
<h3 id="插槽"><a href="#插槽" class="headerlink" title="插槽"></a>插槽</h3><p>插槽是vue是为组件的封装者提供的能力，允许开发者在封装组件的时候，把不确定的，希望由用户指定的部分作为插槽</p>
<p><strong>在组件中去写东西比如<Left>Hello</Left>然后把它渲染出来</strong></p>
<p>定义组件的代码里面放一个占位符<solt></solt></p>
<p>这样使用组件的时候可以传东西进来</p>
<p>App.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;Left&gt;</span><br><span class="line">	&lt;p&gt;这是Left组件的内容区域&lt;/p&gt;</span><br><span class="line">&lt;/Left&gt;</span><br></pre></td></tr></table></figure>

<p>Left.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;left-container&quot;&gt;</span><br><span class="line">    &lt;h3&gt;Left 组件&lt;/h3&gt;</span><br><span class="line">    &lt;hr&gt;</span><br><span class="line">    &lt;!-- 声明一个插槽区域 --&gt;</span><br><span class="line">    &lt;slot name=&quot;solt&quot;&gt;&lt;/slot&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<p>官方规定每个插槽都有一个name名称，不写的话默认就叫default</p>
<p>如果我们要指定元素要插到指定的插槽里面去使用<strong>v-slot指令</strong></p>
<p>App.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;Left&gt;</span><br><span class="line">	&lt;template v-slot:default&gt;</span><br><span class="line">		&lt;p&gt;这是Left组件的内容区域&lt;/p&gt;</span><br><span class="line">	&lt;/template&gt;</span><br><span class="line">&lt;/Left&gt;</span><br></pre></td></tr></table></figure>

<p>Left.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;slot name=&quot;default&quot;&gt;&lt;/slot&gt;</span><br></pre></td></tr></table></figure>

<ul>
<li>v-slot后面要跟上插槽的名字</li>
<li>v-slot指令不能直接用在元素身上,要用在template标签身上</li>
<li>template标签不会渲染为一个元素，是一个虚拟的标签，只起到包裹的作用</li>
<li>v-slot 的简写形式是 #</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;Left&gt;</span><br><span class="line">	&lt;template #default&gt;</span><br><span class="line">		&lt;p&gt;这是Left组件的内容区域&lt;/p&gt;</span><br><span class="line">	&lt;/template&gt;</span><br><span class="line">&lt;/Left&gt;</span><br></pre></td></tr></table></figure>

<p>需求：如果用户没有在插槽放内容如何设置一个默认的内容呢,官方叫<strong>后备内容</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;slot name=&quot;default&quot;&gt;默认内容&lt;/slot&gt;</span><br></pre></td></tr></table></figure>

<h4 id="具名插槽的定义和使用"><a href="#具名插槽的定义和使用" class="headerlink" title="具名插槽的定义和使用"></a>具名插槽的定义和使用</h4><p>以后的开发中，可能会用到移动端的组件库Vant<a target="_blank" rel="noopener" href="https://vant-contrib.gitee.io/vant/#/zh-CN/nav-bar">Vant - 轻量、可靠的移动端组件库 (gitee.io)</a></p>
<p>比如Vant的<strong>navbar</strong>组件就使用了插槽来设计</p>
<p>代码示例：<strong>通过插槽自定义导航栏两侧的内容。</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;van-nav-bar title=&quot;标题&quot; left-text=&quot;返回&quot; left-arrow&gt;</span><br><span class="line">  &lt;template #right&gt;</span><br><span class="line">    &lt;van-icon name=&quot;search&quot; size=&quot;18&quot; /&gt;</span><br><span class="line">  &lt;/template&gt;</span><br><span class="line">&lt;/van-nav-bar&gt;</span><br></pre></td></tr></table></figure>

<p>这个组件的插槽</p>
<p><strong>Slots</strong></p>
<table>
<thead>
<tr>
<th align="left">名称</th>
<th align="left">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="left">title</td>
<td align="left">自定义标题</td>
</tr>
<tr>
<td align="left">left</td>
<td align="left">自定义左侧区域内容</td>
</tr>
<tr>
<td align="left">right</td>
<td align="left">自定义右侧区域内容</td>
</tr>
</tbody></table>
<p>所以设计组件一般有多个插槽，每个插槽都有名字，有名字的插槽就叫<strong>具名插槽</strong></p>
<p>Article.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 文章的标题 --&gt;</span><br><span class="line">&lt;div class=&quot;header-box&quot;&gt;</span><br><span class="line">  &lt;slot name=&quot;title&quot;&gt;&lt;/slot&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 文章的内容 --&gt;</span><br><span class="line">&lt;div class=&quot;content-box&quot;&gt;</span><br><span class="line">  &lt;slot name=&quot;content&quot;&gt;&lt;/slot&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 文章的作者 --&gt;</span><br><span class="line">&lt;div class=&quot;footer-box&quot;&gt;</span><br><span class="line">  &lt;slot name=&quot;footer&quot;&gt;&lt;/slot&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure>

<p>App.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;Article&gt;</span><br><span class="line">  &lt;template #title&gt;</span><br><span class="line">    &lt;h3&gt;一首诗&lt;/h3&gt;</span><br><span class="line">  &lt;/template&gt;</span><br><span class="line">  &lt;template #content&gt;</span><br><span class="line">    &lt;h3&gt;内容&lt;/h3&gt;</span><br><span class="line">  &lt;/template&gt;</span><br><span class="line">  &lt;template #footer&gt;</span><br><span class="line">    &lt;h3&gt;作者&lt;/h3&gt;</span><br><span class="line">  &lt;/template&gt;</span><br><span class="line">&lt;/Article&gt;</span><br></pre></td></tr></table></figure>

<h4 id="作用域插槽"><a href="#作用域插槽" class="headerlink" title="作用域插槽"></a>作用域插槽</h4><p>我们可以在插槽里定义msg属性</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;slot name=&quot;content&quot; msg=&quot;hello vue.js&quot;&gt;&lt;/slot&gt;</span><br></pre></td></tr></table></figure>

<p>在使用插槽的时候可以接收</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;template #content=&quot;obj&quot;&gt;</span><br><span class="line">  &lt;h3&gt;内容&lt;/h3&gt;</span><br><span class="line">  &lt;p&gt;双大括号 obj 双大括号&lt;/p&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<p>页面上显示的是：{ “msg”: “hello vue.js” }   一个对象，要显示内容的话：**<p>双大括号 obj.msg 双大括号</p>**</p>
<p><strong>有名字又有数据的插槽就是作用域插槽</strong></p>
<p>动态绑定用法：Article插槽内定义属性userinfo</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">userinfo</span>: &#123;</span><br><span class="line">      <span class="attr">name</span>: <span class="string">&#x27;张三&#x27;</span>,</span><br><span class="line">      <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>绑定插槽标签</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;slot name=&quot;content&quot; msg=&quot;hello vue.js&quot; :user=&quot;userinfo&quot;&gt;&lt;/slot&gt;</span><br></pre></td></tr></table></figure>

<p>使用的时候也可以进行解构赋值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;template #content=&quot;&#123; msg,user&#125;&quot;&gt;</span><br><span class="line">	&lt;h3&gt;内容&lt;/h3&gt;</span><br><span class="line">	&lt;p&gt;双大括号 msg 双大括号&lt;/p&gt;</span><br><span class="line">	&lt;p&gt;双大括号 user.name 双大括号&lt;/p&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<h4 id="基于插槽对购物车案例进行修改"><a href="#基于插槽对购物车案例进行修改" class="headerlink" title="基于插槽对购物车案例进行修改"></a>基于插槽对购物车案例进行修改</h4><p>Count组件用插槽来实现，我们用eventBus实现了count组件和app的通信，但是还是挺绕的</p>
<p>使用插槽实现：在Goods组件中count的位置定义一个slot插槽</p>
<p>Goods.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 商品的数量 --&gt;</span><br><span class="line">&lt;slot&gt;&lt;/slot&gt;</span><br></pre></td></tr></table></figure>

<p>在App.vue的Goods组件标签内使用Count组件(省略指令)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;Goods&gt;</span><br><span class="line">	&lt;Counter&gt;&lt;/Counter&gt;</span><br><span class="line">&lt;/Goods&gt;</span><br></pre></td></tr></table></figure>

<p>加上name属性的用法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;slot name=&quot;default&quot;&gt;&lt;/slot&gt;</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Counter v-slot:default&gt;&lt;/Counter&gt;</span><br></pre></td></tr></table></figure>

<p>组件已经渲染完毕了，功能的实现怎么写呢</p>
<p>Goods数组里第七个项的数量是2，首先先把每一项的数量值传过去显示出来，既然App.vue里直接使用的Count组件，那么直接传值就可以了，Count组件里定义props来接收</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;span class=&quot;number-box&quot;&gt;双大括号 num 双大括号&lt;/span&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    num: &#123;</span><br><span class="line">      default: 1,</span><br><span class="line">      type: Number</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Counter v-slot:default :num=&quot;item.goods_count&quot;&gt;&lt;/Counter&gt;</span><br></pre></td></tr></table></figure>

<p>点击加号增加数量操作，通过子传父来实现，<strong>自定义事件</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;button type=&quot;button&quot; class=&quot;btn btn-light btn-sm&quot; @click=&quot;add&quot;&gt;+&lt;/button&gt;</span><br></pre></td></tr></table></figure>

<p>App.vue获取发过来的值</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;Footer :isfull=&quot;fullState&quot; :amount=&quot;amt&quot; :all=&quot;total&quot; @full-change=&quot;getFullState&quot;&gt;&lt;/Footer&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">	methods: &#123;</span><br><span class="line">    	// 获取count组件发送过来的最新数量值</span><br><span class="line">    	getNewNum(val) &#123;</span><br><span class="line">      		console.log(val)</span><br><span class="line">    	&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>我们要修改值，要两个参数id和数量</p>
<p>写法：直接传item过来再点出来id，只传item的话，原来的值就被覆盖了，就可以用$event</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Counter v-slot:default :num=&quot;item.goods_count&quot; @num-change=&quot;getNewNum(item,$event)&quot;&gt;&lt;/Counter&gt;</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取count组件发送过来的最新数量值，赋值给当前项的goods_count</span></span><br><span class="line"><span class="function"><span class="title">getNewNum</span>(<span class="params">item,val</span>)</span> &#123;</span><br><span class="line">  item.goods_count = val</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>点击减号的方法也同理</p>
<h3 id="自定义指令"><a href="#自定义指令" class="headerlink" title="自定义指令"></a>自定义指令</h3><p><strong>vue提供了像v-for，v-on，v-bind这些内置指令，如何使用自定义的指令呢</strong></p>
<p>vue提供了</p>
<ul>
<li>私有自定义指令</li>
<li>全局的自定义指令</li>
</ul>
<h4 id="私有自定义指令"><a href="#私有自定义指令" class="headerlink" title="私有自定义指令"></a>私有自定义指令</h4><p>在每个vue组件中，可以在<strong>directives</strong>节点下声明私有自定义指令，示例代码如下，包含固定写法</p>
<h5 id="bind函数"><a href="#bind函数" class="headerlink" title="bind函数"></a>bind函数</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 私有自定义指令</span></span><br><span class="line"><span class="attr">directives</span>: &#123;</span><br><span class="line">  <span class="comment">// 定义一个名为color的指令，指向一个配置对象，用法v-color</span></span><br><span class="line">  <span class="attr">color</span>: &#123;</span><br><span class="line">    <span class="comment">// 当v-color指令绑定到元素身上时，会立即触发bind(el)函数</span></span><br><span class="line">    <span class="function"><span class="title">bind</span>(<span class="params">el</span>)</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">&quot;触发了v-color的bind函数&quot;</span>)</span><br><span class="line">      el.style.color = <span class="string">&#x27;red&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>指令接收，字符串要用‘’单引号包裹起来，不包裹起来就是变量了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;h1 v-color=&quot;color&quot;&gt;App 根组件&lt;/h1&gt;</span><br><span class="line">&lt;h1 v-color=&quot;&#x27;red&#x27;&quot;&gt;App字体&lt;/h1&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      color: &#x27;blue&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  directives: &#123;</span><br><span class="line">    // 定义一个名为color的指令，指向一个配置对象，用法v-color</span><br><span class="line">    color: &#123;</span><br><span class="line">      // 当v-color指令绑定到元素身上时，会立即触发bind(el)函数</span><br><span class="line">      bind(el,binding) &#123;</span><br><span class="line">        console.log(&quot;触发了v-color的bind函数&quot;)</span><br><span class="line">        el.style.color = binding.value</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>按钮点击改变color的值，但是页面元素没有被改变，因为指令没有被触发</p>
<p>如果我们希望改变color的值时候也会更新呢</p>
<h5 id="update函数"><a href="#update函数" class="headerlink" title="update函数"></a>update函数</h5><p><strong>每次DOM元素更新的时候会调用update函数</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">color: &#123;</span><br><span class="line">      <span class="comment">// 当v-color指令绑定到元素身上时，会立即触发bind(el)函数</span></span><br><span class="line">      <span class="function"><span class="title">bind</span>(<span class="params">el,binding</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;触发了v-color的bind函数&quot;</span>)</span><br><span class="line">        el.style.color = binding.value</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="function"><span class="title">update</span>(<span class="params">el,binding</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;触发了v-color的update函数&quot;</span>)</span><br><span class="line">        el.style.color = binding.value</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>简写：如果update里面和bind里面的代码是相同的可以简写，对象格式的自定义指令可以简写成<strong>函数的形式</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">color</span>(<span class="params">el,binding</span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;触发了v-color的函数&quot;</span>)</span><br><span class="line">  el.style.color = binding.value</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="全局自定义指令"><a href="#全局自定义指令" class="headerlink" title="全局自定义指令"></a>全局自定义指令</h4><p>私有指令定义在组件里面了，其他使用不了</p>
<p>如何定义全局自定义指令，像之前定义全局过滤器一样的方法（都要放到main.js里面去）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">// 参数1：字符串，表示全局自定义指令的名字</span><br><span class="line">// 参数2：对象，用来接收指令的参数值</span><br><span class="line">Vue.directive(&#x27;color&#x27;, function(el, binding) &#123;</span><br><span class="line">    el.style.color = binding.value</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h3 id="ESLint"><a href="#ESLint" class="headerlink" title="ESLint"></a>ESLint</h3><p>可组装的JavaScript和JSX检查工具<a target="_blank" rel="noopener" href="https://eslint.bootcss.com/">ESLint - 插件化的 JavaScript 代码检测工具 - ESLint中文文档 (bootcss.com)</a></p>
<p>vue create demo-3创建项目，一路创建项目过来，勾选了Linter之后，会多出一项<strong>选择ESlint的语法规范</strong></p>
<figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ESLint with error prevention only</span><br><span class="line">  ESLint + Airbnb config</span><br><span class="line">  ESLint + Standard config</span><br><span class="line">  ESLint + Prettier</span><br></pre></td></tr></table></figure>

<p>这里我们选择<strong>ESLint + Standard config</strong>标准配置，然后</p>
<blockquote>
<p>(*) Lint on save     //保存代码的时候检查代码规范<br>( ) Lint and fix on commit    //提交代码的时候检查和修复</p>
</blockquote>
<p>.eslintrc.js就是eslint的配置文件了</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">rules: &#123;</span><br><span class="line">  <span class="string">&#x27;no-console&#x27;</span>: process.env.NODE_ENV === <span class="string">&#x27;production&#x27;</span> ? <span class="string">&#x27;warn&#x27;</span> : <span class="string">&#x27;off&#x27;</span>,</span><br><span class="line">  <span class="string">&#x27;no-debugger&#x27;</span>: process.env.NODE_ENV === <span class="string">&#x27;production&#x27;</span> ? <span class="string">&#x27;warn&#x27;</span> : <span class="string">&#x27;off&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>no-console 是禁止使用 console的方法，因为被认为是一个调试的行为</p>
<p>这一句表示：只有在production模式会报警告，开发模式不会报警告</p>
<p><strong>ESLint有各种各样的规则，直接去官网看就好了</strong></p>
<p>常见的语法规则有</p>
<table>
<thead>
<tr>
<th>序号</th>
<th>规则名称</th>
<th>规则约束/默认约束</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>quotes</td>
<td>默认：字符串需要使用单引号包裹</td>
</tr>
<tr>
<td>2</td>
<td>key-spacing</td>
<td>默认：对象的属性和值之间，需要有一个空格分割</td>
</tr>
<tr>
<td>3</td>
<td>comma-dangle</td>
<td>默认：对象或数组的末尾，不允许出现多余的逗号</td>
</tr>
<tr>
<td>4</td>
<td>no-multiple-empty-lines</td>
<td>不允许出现多个空行</td>
</tr>
<tr>
<td>5</td>
<td>no-trailing-spaces</td>
<td>不允许在行尾出现多余的空格</td>
</tr>
<tr>
<td>6</td>
<td>eol-last</td>
<td>默认：文件的末尾必须保留一个空行</td>
</tr>
<tr>
<td>7</td>
<td>spaced-comment</td>
<td>在注释中的<code>//</code>或<code>/*</code>后强制使用一致的间距</td>
</tr>
<tr>
<td>8</td>
<td>indent</td>
<td>强制一致的缩进</td>
</tr>
<tr>
<td>9</td>
<td>import/first</td>
<td><code>import</code> 导入模块的语句必须声明在文件的顶部</td>
</tr>
<tr>
<td>10</td>
<td>space-before-function-paren</td>
<td>方法的形参之前是否需要保留一个空格</td>
</tr>
</tbody></table>
<h4 id="配置vscode的ESLint"><a href="#配置vscode的ESLint" class="headerlink" title="配置vscode的ESLint"></a>配置vscode的ESLint</h4><p>可以参考网上百度的，也可以在b站搜索黑马前端笔记参考</p>
<p>安装ESLint插件和prettier插件，打开vscode设置,setting.json</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;editor.tabSize&quot;</span>: <span class="number">2</span>,</span><br><span class="line">    <span class="string">&quot;editor.formatOnSave&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="comment">// ESLint配置</span></span><br><span class="line">    <span class="string">&quot;editor.codeActionsOnSave&quot;</span>: &#123;</span><br><span class="line">        <span class="attr">&quot;source.fixAll&quot;</span>: <span class="literal">true</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="string">&quot;prettier.configPath&quot;</span>: <span class="string">&quot;C:\\Users\\40919\\.prettierrc&quot;</span>,</span><br><span class="line">    <span class="string">&quot;eslint.alwaysShowStatus&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="string">&quot;prettier.trailingComma&quot;</span>: <span class="string">&quot;none&quot;</span>,</span><br><span class="line">    <span class="string">&quot;prettier.semi&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="comment">// 每行文字个数超过此限制会被迫换行</span></span><br><span class="line">    <span class="string">&quot;prettier.printWidth&quot;</span>: <span class="number">300</span>,</span><br><span class="line">    <span class="comment">// 使用单引号替换双引号</span></span><br><span class="line">    <span class="string">&quot;prettier.singleQuote&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="string">&quot;prettier.arrowParens&quot;</span>: <span class="string">&quot;avoid&quot;</span>,</span><br><span class="line">    <span class="comment">// 设置.vue文件中,HTML代码格式化插件</span></span><br><span class="line">    <span class="string">&quot;vetur.format.defaultFormatter.html&quot;</span>: <span class="string">&quot;js-beautify-html&quot;</span>,</span><br><span class="line">    <span class="string">&quot;vetur.ignoreProjectWarning&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="string">&quot;vetur.format.defaultFormatterOptions&quot;</span>: &#123;</span><br><span class="line">        <span class="attr">&quot;js-beautify-html&quot;</span>: &#123;</span><br><span class="line">            <span class="attr">&quot;wrap_attributes&quot;</span>: <span class="literal">false</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">&quot;prettier&quot;</span>: &#123;</span><br><span class="line">            <span class="attr">&quot;trailingComma&quot;</span>: <span class="string">&quot;none&quot;</span>,</span><br><span class="line">            <span class="attr">&quot;semi&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">&quot;printWidth&quot;</span>: <span class="number">300</span>,</span><br><span class="line">            <span class="attr">&quot;singleQuote&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">            <span class="attr">&quot;arrowParens&quot;</span>: <span class="string">&quot;avoid&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>问题：遇到了导入后，保存ctrl+s的时候格式化代码，首先选择格式化代码方式为prettier，<strong>格式化的时候会变成双引号和结尾加逗号和分号</strong></p>
<p>解决办法：在项目文件中在放一个.prettierrc文件，<strong>这个优先级是最高的</strong></p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;semi&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">&quot;singleQuote&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="attr">&quot;trailingComma&quot;</span>: <span class="string">&quot;none&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="封装Axios"><a href="#封装Axios" class="headerlink" title="封装Axios"></a>封装Axios</h3><p>首先安装Axios，npm i axios -S</p>
<p>创建两个组件Left和RIght</p>
<p>在Left里面发起<strong>get请求</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;button @click=&quot;getInfo&quot;&gt;发起GET请求&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;Left&#x27;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    async getInfo () &#123;</span><br><span class="line">      await axios.get(&#x27;http://www.liulongbin.top:3006/api/get&#x27;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在Right里面发起Post请求</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;Right&#x27;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    async postInfo () &#123;</span><br><span class="line">      const &#123; data: res &#125; = await axios.post(&#x27;http://www.liulongbin.top:3006/api/post&#x27;, &#123; name: &#x27;zs&#x27;, age: 20 &#125;)</span><br><span class="line">      console.log(res)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>这样每个组件都要发起请求是不是很麻烦，所以要封装起来，在main.js中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line">Vue.prototype.$http = axios</span><br></pre></td></tr></table></figure>

<p>之后在组件里写就是</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> <span class="built_in">this</span>.$http.post(<span class="string">&#x27;http://www.liulongbin.top:3006/api/post&#x27;</span>, &#123; <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;)</span><br></pre></td></tr></table></figure>

<p>配置全局的链接请求，在main.js里面配置</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 全局配置axios请求根路径</span></span><br><span class="line">axios.defaults.baseURL = <span class="string">&#x27;http://www.liulongbin.top:3006&#x27;</span></span><br></pre></td></tr></table></figure>

<p>请求</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> axios.get(<span class="string">&#x27;/api/get&#x27;</span>)</span><br></pre></td></tr></table></figure>

<h4 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h4><p><strong>无法实现api接口的复用</strong></p>
<h3 id="路由"><a href="#路由" class="headerlink" title="路由"></a>路由</h3><p>前端路由的概念和原理</p>
<p>SPA和前端路由</p>
<p>router，路由就是对应关系，点击hash地址，页面上的组件会发生改变</p>
<p><strong>就是hash地址和组件之间的对应关系</strong></p>
<p>前端路由工作方式：</p>
<ol>
<li>用户点击页面上的路由链接</li>
<li>导致URL地址栏上的Hash地址发生改变</li>
<li>前端路由监听到hash地址的变化</li>
<li>前端路由把当前Hash地址对应的组件渲染到浏览器中</li>
</ol>
<p><img src="https://s4.ax1x.com/2022/01/14/78UPRe.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/14/78UPRe.png" srcset=""></p>
<p>实现简易的前端路由</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href=&quot;#/home&quot;&gt;首页&lt;/a&gt;</span><br><span class="line">&lt;a href=&quot;#/movie&quot;&gt;电影&lt;/a&gt;</span><br><span class="line">&lt;a href=&quot;#/about&quot;&gt;关于&lt;/a&gt;</span><br><span class="line">&lt;!-- 动态展示组件 --&gt;</span><br><span class="line">&lt;component :is=&quot;comName&quot;&gt;&lt;/component&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">// 导入组件</span><br><span class="line">import Home from &#x27;@/components/Home.vue&#x27;</span><br><span class="line">import Movie from &#x27;@/components/Movie.vue&#x27;</span><br><span class="line">import About from &#x27;@/components/About.vue&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 在动态组件的位置，要展示的组件的名字，值必须是字符串</span><br><span class="line">      comName: &#x27;Home&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    // 只要当前的 App 组件一被创建，就立即监听 window 对象的 onhashchange 事件</span><br><span class="line">    // 对应的更改comName的值</span><br><span class="line">    window.onhashchange = () =&gt; &#123;</span><br><span class="line">      console.log(&#x27;监听到了 hash 地址的变化&#x27;, location.hash)</span><br><span class="line">      switch (location.hash) &#123;</span><br><span class="line">        case &#x27;#/home&#x27;:</span><br><span class="line">          this.comName = &#x27;Home&#x27;</span><br><span class="line">          break</span><br><span class="line">        case &#x27;#/movie&#x27;:</span><br><span class="line">          this.comName = &#x27;Movie&#x27;</span><br><span class="line">          break</span><br><span class="line">        case &#x27;#/about&#x27;:</span><br><span class="line">          this.comName = &#x27;About&#x27;</span><br><span class="line">          break</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  // 注册组件</span><br><span class="line">  components: &#123;</span><br><span class="line">    Home,</span><br><span class="line">    Movie,</span><br><span class="line">    About</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h3 id="vue-router"><a href="#vue-router" class="headerlink" title="vue-router"></a>vue-router</h3><p>vue-router是vue.js官方给出的路由解决方案，只能结合vue项目使用，能够轻松管理SPA项目中组件的切换</p>
<p><a target="_blank" rel="noopener" href="https://router.vuejs.org/zh/">Vue Router (vuejs.org)</a></p>
<p>vue-router安装和配置</p>
<ol>
<li>安装vue-router包</li>
<li>创建路由模块</li>
<li>导入并挂载路由模块</li>
<li>声明路由链接和占位符</li>
</ol>
<h4 id="在项目中安装vue-router"><a href="#在项目中安装vue-router" class="headerlink" title="在项目中安装vue-router"></a>在项目中安装vue-router</h4><p>在vue2项目中，安装vue-router的命令如下</p>
<figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i vue<span class="literal">-router</span>@<span class="number">3.5</span>.<span class="number">2</span> <span class="literal">-S</span></span><br></pre></td></tr></table></figure>

<h4 id="创建路由模块"><a href="#创建路由模块" class="headerlink" title="创建路由模块"></a>创建路由模块</h4><p>在src源代码目录下，创建router/index.js路由模块，并初始化如下的代码:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.导入Vue和VueRouter的包</span></span><br><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> VueRouter <span class="keyword">from</span> <span class="string">&#x27;vue-router&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2.调用Vue.use()函数，把VueRouter安装位Vue的插件</span></span><br><span class="line">Vue.use(VueRouter)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3.创建路由的实例对象</span></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4.向外共享路由的实例对象</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> router</span><br></pre></td></tr></table></figure>

<p>写完以后，在main.js里面挂载</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入路由模块，目的：拿到路由的实例对象</span></span><br><span class="line"><span class="comment">// 在进行模块化导入的时候，如果给定的是文件夹，则默认导入这个文件夹下，名字叫做 index.js 的文件</span></span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">&#x27;@/router&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  <span class="attr">render</span>: <span class="function"><span class="params">h</span> =&gt;</span> h(App),</span><br><span class="line">  <span class="comment">// 在 Vue 项目中，要想把路由用起来，必须把路由实例对象，通过下面的方式进行挂载</span></span><br><span class="line">  <span class="comment">// router: 路由的实例对象</span></span><br><span class="line">  router</span><br><span class="line">&#125;).$mount(<span class="string">&#x27;#app&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>以后如果创建项目时选择了vue-router会自动创建文件</p>
<p>使用App2.vue来写入</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href=&quot;#/home&quot;&gt;首页&lt;/a&gt;</span><br><span class="line">&lt;a href=&quot;#/movie&quot;&gt;电影&lt;/a&gt;</span><br><span class="line">&lt;a href=&quot;#/about&quot;&gt;关于&lt;/a&gt;</span><br><span class="line">&lt;hr&gt;</span><br><span class="line">&lt;!-- 只要项目中安装和配置了vue-router,就可以使用vue-router组件了 --&gt;</span><br><span class="line">&lt;!-- 它的作用是：占位符 --&gt;</span><br><span class="line">&lt;router-view&gt;&lt;/router-view&gt;</span><br></pre></td></tr></table></figure>

<p>点击标签会显示组件，显示位置就是占位符所在的位置</p>
<p>在路由模块router/index.js中写对应关系</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入需要的组件</span></span><br><span class="line"><span class="keyword">import</span> Home <span class="keyword">from</span> <span class="string">&#x27;@/components/Home.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Movie <span class="keyword">from</span> <span class="string">&#x27;@/components/Movie.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> About <span class="keyword">from</span> <span class="string">&#x27;@/components/About.vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter(&#123;</span><br><span class="line">  <span class="comment">// routes 是一个数组，作用：定义 “hash 地址” 与 “组件” 之间的对应关系</span></span><br><span class="line">  <span class="attr">routes</span>: [</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 路由规则</span></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>, <span class="attr">component</span>: Home &#125;,</span><br><span class="line"></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;/movie&#x27;</span>, <span class="attr">component</span>: Movie &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;/about&#x27;</span>, <span class="attr">component</span>: About &#125;</span><br></pre></td></tr></table></figure>

<p>安装了vue-router后不用谢a链接标签来切换了</p>
<p>使用<router-link></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- router-link替代a链接 --&gt;</span><br><span class="line">&lt;router-link to=&quot;/home&quot;&gt;首页&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/movie&quot;&gt;电影&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/about&quot;&gt;关于&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<h4 id="路由重定向"><a href="#路由重定向" class="headerlink" title="路由重定向"></a>路由重定向</h4><p>要设置没有后缀的地址，默认进入的行为</p>
<p><strong>路由重定向指的是：用户在访问地址A的时候，强制用户跳转到地址C，从而展示特定的组件页面</strong></p>
<p><strong>通过路由规则的redirect属性，指定一个新的路由地址，可以很方便的设置路由的重定向</strong></p>
<p>相当于主页功能，一进入就展示某个页面</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 当用户访问 / 地址的时候，通过redirect属性跳转到 /home 对应的路由规则</span></span><br><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/&#x27;</span>, <span class="attr">redirect</span>: <span class="string">&#x27;/home&#x27;</span> &#125;,</span><br></pre></td></tr></table></figure>

<h4 id="嵌套路由"><a href="#嵌套路由" class="headerlink" title="嵌套路由"></a>嵌套路由</h4><p>通过路由实现组件的嵌套展示，叫做嵌套路由</p>
<p>展示的模板中又有路由链接，点击又可以切换显示内容</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-link to=&quot;/about/tab1&quot;&gt;tab1&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/about/tab2&quot;&gt;tab2&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<p>路由模块index.js里，声明嵌套路由</p>
<p>通过children属性声明子路由规则，在about的规则节点下</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/about&#x27;</span>,</span><br><span class="line">  <span class="attr">component</span>: About,</span><br><span class="line">  <span class="comment">// redirect属性，默认一进入about页面就展示tab1组件</span></span><br><span class="line">  <span class="comment">// redirect: &#x27;/about/tab1&#x27;,</span></span><br><span class="line">  <span class="attr">children</span>: [</span><br><span class="line">    <span class="comment">// 子路由规则</span></span><br><span class="line">    <span class="comment">// 默认子路由：如果 children 数组中，某个路由规则的 path 值为空字符串，则这条路由规则，叫做“默认子路由”</span></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;&#x27;</span>, <span class="attr">component</span>: Tab1 &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;tab2&#x27;</span>, <span class="attr">component</span>: Tab2 &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<p><strong>默认子路由：如果 children 数组中，某个路由规则的 path 值为空字符串，则这条路由规则，叫做“默认子路由”</strong></p>
<p>如果开启了默认子路由，就要修改路径，因为默认会展示出来</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-link to=&quot;/about&quot;&gt;tab1&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<h4 id="动态路由匹配"><a href="#动态路由匹配" class="headerlink" title="动态路由匹配"></a>动态路由匹配</h4><p>假设页面上电影详情的实现是</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-link to=&quot;/movie/1&quot;&gt;电影1&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/movie/2&quot;&gt;电影2&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/movie/3&quot;&gt;电影3&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<p>路由是这样吗</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/movie/1&#x27;</span>, <span class="attr">component</span>: Movie &#125;,</span><br><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/movie/2&#x27;</span>, <span class="attr">component</span>: Movie &#125;,</span><br><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/movie/3&#x27;</span>, <span class="attr">component</span>: Movie &#125;</span><br></pre></td></tr></table></figure>

<p>如果有一万个电影，那么详情页面肯定不是这样写</p>
<p><strong>动态路由是指：把Hash地址中可变的部分定义为参数项，提高路由的复用性</strong></p>
<p><strong>在vue-router中使用英文的冒号：来定义路由的参数项。</strong></p>
<h4 id="参数项"><a href="#参数项" class="headerlink" title="参数项"></a>参数项</h4><p>根据路径展示组件</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-link to=&quot;/movie/1&quot;&gt;电影1&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/movie/2&quot;&gt;电影2&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/movie/3&quot;&gt;电影3&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/movie/:id&#x27;</span>, <span class="attr">component</span>: Movie &#125;,</span><br></pre></td></tr></table></figure>

<p>再根据id值展示相应的内容</p>
<p>打印组件实例this，在route的这个属性下，是一个对象，这个对象里面param属性就是id值</p>
<p>通过id我们可以拿到相关的数据用来展示了</p>
<ul>
<li>this.$route 是路由的“参数对象”</li>
<li>this.$router 是路由的“导航对象”</li>
</ul>
<p>第二种拿参数的方式</p>
<p>在配置路由中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/movie/:id&#x27;</span>, <span class="attr">component</span>: Movie ,<span class="attr">props</span>: <span class="literal">true</span>&#125;,</span><br></pre></td></tr></table></figure>

<p>Movie.vue中</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;Movie&#x27;,</span><br><span class="line">  // 接收 props 数据</span><br><span class="line">  props: [&#x27;id&#x27;],</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>在hash地址中，在斜线  /  后面的参数叫做路径参数</strong></p>
<p>在hash地址中，？后面的参数叫做查询参数</p>
<p>使用this.$route.query来访问查询参数</p>
<p>/movie/2?name=zs&amp;age=20 是 fullPath 值</p>
<p>/movie/2 是 path 值</p>
<h4 id="导航"><a href="#导航" class="headerlink" title="导航"></a>导航</h4><p>在浏览器中，点击链接实现导航的方式，叫做<strong>声明式的导航</strong>。例如：</p>
<p>在普通网页中点击<a>链接，vue项目中点击<router-link>都属于声明式导航</p>
<p>在浏览器中，调用API的方法实现导航的方式，叫做<strong>编程式导航</strong>。例如：</p>
<p>普通网页中，调用location.href跳转到新页面的方式，属于编程式导航</p>
<p>vue-router提供了很多编程式导航的API，其中最常用的导航API分别是</p>
<ul>
<li>this.$router.push(‘hash地址’)，会新增一条历史记录</li>
<li>this.$router.replace(‘hash地址’)，会替换当前历史记录</li>
<li>this.$router.go(数值n)，调用方法可以在浏览历史中前进和后退，前进是1，后退是-1</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">gotoMK</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	<span class="comment">// 通过编程式导航 API，导航跳转到指定的页面</span></span><br><span class="line">	<span class="built_in">this</span>.$router.push(<span class="string">&#x27;/movie/1&#x27;</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="title">gotoLk2</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	<span class="built_in">this</span>.$router.replace(<span class="string">&#x27;/movie/2&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">goback</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	<span class="comment">// go(-1) 表示后退一层</span></span><br><span class="line">	<span class="comment">// 如果后退的层数超过上限，则原地不动</span></span><br><span class="line">	<span class="built_in">this</span>.$router.go(-<span class="number">1</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在行内使用编程式导航this必须要省略，否则会报错</p>
<h4 id="导航守卫"><a href="#导航守卫" class="headerlink" title="导航守卫"></a>导航守卫</h4><p>导航守卫可以控制路由的访问权限</p>
<p>登录后台页面，检测到未登录的话，会跳转到登录页面</p>
<h5 id="1-全局前置守卫"><a href="#1-全局前置守卫" class="headerlink" title="1.全局前置守卫"></a>1.全局前置守卫</h5><p>在每次发生路由的导航跳转时，都会触发全局前置守卫，因此，在全局前置守卫中，程序员可以对每个路由进行访问权限的控制：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.创建路由实例对象</span></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter(&#123;...&#125;)</span><br><span class="line">                              </span><br><span class="line"><span class="comment">// 调用路由实例对象的 beforeEach 方法，即可声明“全局前置守卫”</span></span><br><span class="line"><span class="comment">// 每次发生路由导航跳转时，就会触发 fn 这个 “回调函数”</span></span><br><span class="line">router.beforeEach(fn)</span><br></pre></td></tr></table></figure>

<p>在路由模块中,index.js定义方法</p>
<h5 id="2-守卫方法的三个形参"><a href="#2-守卫方法的三个形参" class="headerlink" title="2.守卫方法的三个形参"></a>2.守卫方法的三个形参</h5><ul>
<li> to 表示将要访问的路由的信息对象，比如进入home页面，to就是这个页面</li>
<li>from 表示将要离开的路由的信息对象</li>
<li>next() 函数表示放行的意思</li>
</ul>
<p>假设用户拥有后台主页的访问权限，直接放行：next()</p>
<p>假设用户没用后台主页访问权限，强行跳转到登录页面：next(‘/login’)</p>
<p>当前用户没有后台主页访问权限，不允许跳转到后台主页：next(false)</p>
<p>例子：新增两个页面</p>
<p>index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Login <span class="keyword">from</span> <span class="string">&#x27;@/components/Login.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Main <span class="keyword">from</span> <span class="string">&#x27;@/components/Main.vue&#x27;</span></span><br><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/login&#x27;</span>, <span class="attr">component</span>: Login &#125;,</span><br><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;/main&#x27;</span>, <span class="attr">component</span>: Main &#125;</span><br></pre></td></tr></table></figure>

<p>app2.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-link to=&quot;/main&quot;&gt;访问后台主页&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/login&quot;&gt;访问登录页&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<p>index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 为 router 实例对象，声明全局前置导航守卫</span></span><br><span class="line"><span class="comment">// 只要发生了路由的跳转，必然会触发 beforeEach 指定的 function 回调函数</span></span><br><span class="line">router.beforeEach(<span class="function"><span class="keyword">function</span>(<span class="params">to, <span class="keyword">from</span>, next</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// to 表示将要访问的路由的信息对象</span></span><br><span class="line">  <span class="comment">// from 表示将要离开的路由的信息对象</span></span><br><span class="line">  <span class="comment">// next() 函数表示放行的意思</span></span><br><span class="line">  <span class="comment">// 分析：</span></span><br><span class="line">  <span class="comment">// 1. 要拿到用户将要访问的 hash 地址</span></span><br><span class="line">  <span class="comment">// 2. 判断 hash 地址是否等于 /main。</span></span><br><span class="line">  <span class="comment">// 2.1 如果等于 /main，证明需要登录之后，才能访问成功</span></span><br><span class="line">  <span class="comment">// 2.2 如果不等于 /main，则不需要登录，直接放行  next()</span></span><br><span class="line">  <span class="comment">// 3. 如果访问的地址是 /main。则需要读取 localStorage 中的 token 值</span></span><br><span class="line">  <span class="comment">// 3.1 如果有 token，则放行</span></span><br><span class="line">  <span class="comment">// 3.2 如果没有 token，则强制跳转到 /login 登录页</span></span><br><span class="line">  <span class="keyword">if</span> (to.path === <span class="string">&#x27;/main&#x27;</span>) &#123;</span><br><span class="line">    <span class="comment">// 要访问后台主页，需要判断是否有 token</span></span><br><span class="line">    <span class="keyword">const</span> token = <span class="built_in">localStorage</span>.getItem(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> (token) &#123;</span><br><span class="line">      next()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// 没有登录，强制跳转到登录页</span></span><br><span class="line">      next(<span class="string">&#x27;/login&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  <span class="comment">// 如果不是访问/main，可以放行</span></span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    next()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>在浏览器的  应用程序  选项，本地存储中，添加一个token，值随便填</p>
<h3 id="admin后台案例"><a href="#admin后台案例" class="headerlink" title="admin后台案例"></a>admin后台案例</h3><p>安装完包后，运行项目</p>
<p>安装路由模块</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i vue-router@3.5.2 -S</span><br></pre></td></tr></table></figure>

<p>新建router，新建index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> VueRouter <span class="keyword">from</span> <span class="string">&#x27;vue-router&#x27;</span></span><br><span class="line"></span><br><span class="line">Vue.use(VueRouter)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter(&#123;&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> router</span><br></pre></td></tr></table></figure>

<p>打开main.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入路由模块</span></span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">&#x27;@/router&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  <span class="attr">render</span>: <span class="function"><span class="params">h</span> =&gt;</span> h(App),</span><br><span class="line">  router</span><br><span class="line">&#125;).$mount(<span class="string">&#x27;#app&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>在index.js中定义对应关系</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入需要的组件</span></span><br><span class="line"><span class="keyword">import</span> Login <span class="keyword">from</span> <span class="string">&#x27;@/components/MyLogin.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Home <span class="keyword">from</span> <span class="string">&#x27;@/components/MyHome.vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> Users <span class="keyword">from</span> <span class="string">&#x27;@/components/menus/MyUsers.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Rights <span class="keyword">from</span> <span class="string">&#x27;@/components/menus/MyRights.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Goods <span class="keyword">from</span> <span class="string">&#x27;@/components/menus/MyGoods.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Orders <span class="keyword">from</span> <span class="string">&#x27;@/components/menus/MyOrders.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> Settings <span class="keyword">from</span> <span class="string">&#x27;@/components/menus/MySettings.vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> UserDetail <span class="keyword">from</span> <span class="string">&#x27;@/components/user/MyUserDetail.vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter(&#123;</span><br><span class="line">  <span class="attr">routes</span>: [</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;/&#x27;</span>, <span class="attr">redirect</span>: <span class="string">&#x27;/login&#x27;</span> &#125;,</span><br><span class="line">    <span class="comment">// 登录的路由规则</span></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;/login&#x27;</span>, <span class="attr">component</span>: Login &#125;,</span><br><span class="line">    <span class="comment">// 后台主页的路由规则</span></span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>,</span><br><span class="line">      <span class="attr">component</span>: Home,</span><br><span class="line">      <span class="attr">redirect</span>: <span class="string">&#x27;/home/users&#x27;</span>,</span><br><span class="line">      <span class="attr">children</span>: [</span><br><span class="line">        &#123; <span class="attr">path</span>: <span class="string">&#x27;users&#x27;</span>, <span class="attr">component</span>: Users &#125;,</span><br><span class="line">        &#123; <span class="attr">path</span>: <span class="string">&#x27;rights&#x27;</span>, <span class="attr">component</span>: Rights &#125;,</span><br><span class="line">        &#123; <span class="attr">path</span>: <span class="string">&#x27;goods&#x27;</span>, <span class="attr">component</span>: Goods &#125;,</span><br><span class="line">        &#123; <span class="attr">path</span>: <span class="string">&#x27;orders&#x27;</span>, <span class="attr">component</span>: Orders &#125;,</span><br><span class="line">        &#123; <span class="attr">path</span>: <span class="string">&#x27;settings&#x27;</span>, <span class="attr">component</span>: Settings &#125;,</span><br><span class="line">        <span class="comment">// 用户详情页的路由规则</span></span><br><span class="line">        &#123; <span class="attr">path</span>: <span class="string">&#x27;userinfo/:id&#x27;</span>, <span class="attr">component</span>: UserDetail, <span class="attr">props</span>: <span class="literal">true</span> &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>在App.vue中防止占位符标签</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;!-- 占位符 --&gt;</span><br><span class="line">  &lt;router-view&gt;&lt;/router-view&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<h4 id="模拟登录"><a href="#模拟登录" class="headerlink" title="模拟登录"></a>模拟登录</h4><p>定义数据，MyLogin.vue</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">username</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">password</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<p>绑定输入框v-model，.trim是去除空格</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&lt;input</span><br><span class="line">	type=&quot;text&quot;</span><br><span class="line">    class=&quot;form-control ml-2&quot;</span><br><span class="line">    id=&quot;username&quot;</span><br><span class="line">    placeholder=&quot;请输入登录名称&quot;</span><br><span class="line">    autocomplete=&quot;off&quot;</span><br><span class="line">    v-model.trim=&quot;username&quot;</span><br><span class="line">    /&gt;</span><br><span class="line">&lt;input</span><br><span class="line">	type=&quot;password&quot;</span><br><span class="line">	class=&quot;form-control ml-2&quot;</span><br><span class="line">	id=&quot;password&quot;</span><br><span class="line">	placeholder=&quot;请输入登录密码&quot;</span><br><span class="line">	v-model.trim=&quot;password&quot;</span><br><span class="line">	/&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>绑定登录按钮事件，和点击按钮重制框框</p>
<p>登录成功后存放一个假的token，因为现在后端没有token</p>
<p>登录后，调用API方法，跳转页面</p>
<p>登录失败，移除token</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&lt;button type=&quot;button&quot; class=&quot;btn btn-secondary mr-2&quot; @click=&quot;reset&quot;&gt;重置&lt;/button&gt;</span><br><span class="line">&lt;button type=&quot;button&quot; class=&quot;btn btn-primary&quot; @click=&quot;login&quot;&gt;登录&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">    </span><br><span class="line">  methods: &#123;</span><br><span class="line">    reset() &#123;</span><br><span class="line">      this.username = &#x27;&#x27;</span><br><span class="line">      this.password = &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    login() &#123;</span><br><span class="line">      if (this.username === &#x27;admin&#x27; &amp;&amp; this.password === &#x27;666666&#x27;) &#123;</span><br><span class="line">        // 登录成功</span><br><span class="line">        // 1. 存储 token</span><br><span class="line">        localStorage.setItem(&#x27;token&#x27;, &#x27;Bearer xxxx&#x27;)</span><br><span class="line">        // 2. 跳转到后台主页</span><br><span class="line">        this.$router.push(&#x27;/home&#x27;)</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        // 登录失败</span><br><span class="line">        localStorage.removeItem(&#x27;token&#x27;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">    </span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h4 id="token认证时的认证格式"><a href="#token认证时的认证格式" class="headerlink" title="token认证时的认证格式"></a>token认证时的认证格式</h4><p>一般后端会返回token，所以到时候拿到token去setItem就行了</p>
<p>设置好各个组件的路径和对应关系后</p>
<p>然后去渲染后台页面，分成上下部分，下面部分又分为左右部分</p>
<p>在MyHome.vue中导入组件并渲染</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;home-container&quot;&gt;</span><br><span class="line">    &lt;!-- 头部区域 --&gt;</span><br><span class="line">    &lt;MyHeader&gt;&lt;/MyHeader&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">// 头部区域组件</span><br><span class="line">import MyHeader from &#x27;./subcomponents/MyHeader.vue&#x27;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;MyHome&#x27;,</span><br><span class="line">  // 注册组件</span><br><span class="line">  components: &#123;</span><br><span class="line">    MyHeader</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>下方的大区域盒子包含左侧边栏和右边主体</p>
<p>大盒子,写在header下面，之前要导入MyAside组件，然后注册使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">	&lt;!-- 页面主体区域 --&gt;</span><br><span class="line">    &lt;div class=&quot;home-main-box&quot;&gt;</span><br><span class="line">      &lt;!-- 左侧边栏 --&gt;</span><br><span class="line">      &lt;MyAside&gt;&lt;/MyAside&gt;</span><br><span class="line">      &lt;!-- 右侧内容主体区域 --&gt;</span><br><span class="line">      &lt;div class=&quot;home-main-body&quot;&gt;</span><br><span class="line">        &lt;router-view&gt;&lt;/router-view&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">  .home-main-box &#123;</span><br><span class="line">    height: 100%;</span><br><span class="line">    display: flex;</span><br><span class="line">    .home-main-body &#123;</span><br><span class="line">      padding: 15px;</span><br><span class="line">      flex: 1;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<h4 id="实现退出功能"><a href="#实现退出功能" class="headerlink" title="实现退出功能"></a>实现退出功能</h4><p><strong>按钮实现退出并清除token，重新跳转到登录页面</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;button type=&quot;button&quot; class=&quot;btn btn-light&quot; @click=&quot;logout&quot;&gt;退出登录&lt;/button&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;MyHeader&#x27;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    logout() &#123;</span><br><span class="line">      // 1. 清空 token</span><br><span class="line">      localStorage.removeItem(&#x27;token&#x27;)</span><br><span class="line">      // 2. 跳转到登录页面</span><br><span class="line">      this.$router.push(&#x27;/login&#x27;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>之前写的逻辑上是，没有登录的时候如果直接进入/home路径会跳转会/login页面</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 全局前置守卫</span></span><br><span class="line">router.beforeEach(<span class="function"><span class="keyword">function</span>(<span class="params">to, <span class="keyword">from</span>, next</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (to.path === <span class="string">&#x27;/home&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> token = <span class="built_in">localStorage</span>.getItem(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> (token) &#123;</span><br><span class="line">      next()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      next(<span class="string">&#x27;/login&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    next()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h4 id="点击侧边栏按钮，展示主体"><a href="#点击侧边栏按钮，展示主体" class="headerlink" title="点击侧边栏按钮，展示主体"></a><strong>点击侧边栏按钮，展示主体</strong></h4><p>在home路由里面嵌套一些路由子链接</p>
<p>左侧是router-link，右侧放置router-view渲染对应的页面</p>
<p><strong>本来应该放在ul的li标签里面的，这里就省略部分代码</strong></p>
<p>在侧边栏MyAside.vue中，编写跳转链接</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;router-link to=&quot;/home/users&quot;&gt;用户管理&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/home/rights&quot;&gt;权限管理&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/home/goods&quot;&gt;商品管理&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/home/orders&quot;&gt;订单管理&lt;/router-link&gt;</span><br><span class="line">&lt;router-link to=&quot;/home/settings&quot;&gt;系统设置&lt;/router-link&gt;</span><br></pre></td></tr></table></figure>

<p>配置对应的路由，应该是设置对应的子路由</p>
<p>index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 后台主页的路由规则</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>,</span><br><span class="line">  <span class="attr">component</span>: Home,</span><br><span class="line">  <span class="attr">redirect</span>: <span class="string">&#x27;/home/users&#x27;</span>,</span><br><span class="line">  <span class="attr">children</span>: [</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;users&#x27;</span>, <span class="attr">component</span>: Users &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;rights&#x27;</span>, <span class="attr">component</span>: Rights &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;goods&#x27;</span>, <span class="attr">component</span>: Goods &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;orders&#x27;</span>, <span class="attr">component</span>: Orders &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;settings&#x27;</span>, <span class="attr">component</span>: Settings &#125;,</span><br><span class="line">    <span class="comment">// 和其他平级，用户详情页的路由规则</span></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;userinfo/:id&#x27;</span>, <span class="attr">component</span>: UserDetail, <span class="attr">props</span>: <span class="literal">true</span> &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在App.vue对应位置放置<router-view>标签，渲染路由切换时对应的界面</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 页面主体区域 --&gt;</span><br><span class="line">&lt;div class=&quot;home-main-box&quot;&gt;</span><br><span class="line">  &lt;!-- 左侧边栏 --&gt;</span><br><span class="line">  &lt;MyAside&gt;&lt;/MyAside&gt;</span><br><span class="line">  &lt;!-- 右侧内容主体区域 --&gt;</span><br><span class="line">  &lt;div class=&quot;home-main-body&quot;&gt;</span><br><span class="line">    &lt;router-view&gt;&lt;/router-view&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure>

<h4 id="渲染user页面的数据"><a href="#渲染user页面的数据" class="headerlink" title="渲染user页面的数据"></a>渲染user页面的数据</h4><p>在MyUser.vue页面内编写</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;tr v-for=&quot;item in userlist&quot; :key=&quot;item.id&quot;&gt;</span><br><span class="line">  &lt;td&gt;双大括号 item.id 双大括号&lt;/td&gt;</span><br><span class="line">  &lt;td&gt;双大括号 item.name 双大括号&lt;/td&gt;</span><br><span class="line">  &lt;td&gt;双大括号 item.age 双大括号&lt;/td&gt;</span><br><span class="line">  &lt;td&gt;双大括号 item.position 双大括号&lt;/td&gt;</span><br><span class="line">  &lt;td&gt;</span><br><span class="line">    &lt;a href=&quot;#&gt;详情&lt;/a&gt;</span><br><span class="line">  &lt;/td&gt;</span><br><span class="line">&lt;/tr&gt;</span><br></pre></td></tr></table></figure>

<p>点击详情，展示数据的详细情况页面</p>
<p>添加按钮点击事件，传递item的id值，找到对应的数据，跳转到详情页面展示</p>
<p>.prevent 阻止</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href=&quot;#&quot; @click.prevent=&quot;gotoDetail(item.id)&quot;&gt;详情&lt;/a&gt;</span><br></pre></td></tr></table></figure>

<p>通过this.$router.push()跳转到，路径为/home/userinfo  因为和其他userinfo</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  methods: &#123;</span><br><span class="line">    gotoDetail(id) &#123;</span><br><span class="line">      this.$router.push(&#x27;/home/userinfo/&#x27; + id)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>userinfo页面也要定义props，来接收id值，</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;MyUserDetail&#x27;,</span><br><span class="line">  props: [&#x27;id&#x27;]</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>还要配置子路由里带参数的路由选项,在children选项中，参数为id，带参数的时候加“  ：”</p>
<p>并打开props：true选项</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 用户详情页的路由规则</span></span><br><span class="line">&#123; <span class="attr">path</span>: <span class="string">&#x27;userinfo/:id&#x27;</span>, <span class="attr">component</span>: UserDetail, <span class="attr">props</span>: <span class="literal">true</span> &#125;</span><br></pre></td></tr></table></figure>

<p>设置默认跳转到用户管理重定向</p>
<p>在路由设置里，/home节点下，设置重定向的位置（好像也可以使用默认子路由）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 后台主页的路由规则</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>,</span><br><span class="line">  <span class="attr">component</span>: Home,</span><br><span class="line">  <span class="attr">redirect</span>: <span class="string">&#x27;/home/users&#x27;</span>,</span><br></pre></td></tr></table></figure>

<p><strong>注意点：hash地址里面的字母都要小写</strong></p>
<p>开始我们可以判断进入/home页面来判断权限，但是页面多了之后呢</p>
<p>我们可以，定义一个数组，如果路径在数组里面的就判断有没有权限</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">const pathArr = [&#x27;/home&#x27;,&#x27;/home/users&#x27;,&#x27;/home/rights&#x27;]</span><br><span class="line">if (pathArr.indexOf(to.path) != -1) &#123;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>那么数组多了以后不是很方便，我们可以定义一个js文件来存放</p>
<p>pathArr.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> [<span class="string">&#x27;/home&#x27;</span>, <span class="string">&#x27;/home/users&#x27;</span>, <span class="string">&#x27;/home/rights&#x27;</span>]</span><br></pre></td></tr></table></figure>

<p>需要的时候导入使用</p>
<p>index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pathArr <span class="keyword">from</span> <span class="string">&#x27;@/router/pathArr.js&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 全局前置守卫</span></span><br><span class="line">router.beforeEach(<span class="function"><span class="keyword">function</span>(<span class="params">to, <span class="keyword">from</span>, next</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (pathArr.indexOf(to.path) !== -<span class="number">1</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> token = <span class="built_in">localStorage</span>.getItem(<span class="string">&#x27;token&#x27;</span>)</span><br><span class="line">    <span class="keyword">if</span> (token) &#123;</span><br><span class="line">      next()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      next(<span class="string">&#x27;/login&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    next()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h3 id="头条案例"><a href="#头条案例" class="headerlink" title="头条案例"></a>头条案例</h3><p>创建项目，安装路由和eslint</p>
<ol>
<li>vue create toutiao</li>
<li>选择手动配置</li>
<li>选择router和css支持</li>
<li>选择vue2.x版本</li>
<li>会询问是否使用历史模式的路由，这里选择n（兼容性比较差）</li>
<li>选择less预处理器</li>
<li>选择ESLint Standard config，标准配置</li>
<li>ESLint on Save默认即可</li>
<li>配置文件如何放置，选择默认的独立文件保存方式</li>
<li>最后是是否保存预设，都行</li>
</ol>
<p>项目解构</p>
<p>components和views文件夹的区别</p>
<p><strong>如果是通过路由来进行切换展示的组件，要放在views里面</strong></p>
<p><strong>如果某个路由不是通过组件来切换的，是一个可复用的组件那么就，放在components里面</strong></p>
<p>比如home页面就放在了views文件夹里面</p>
<p>在App.vue中重新编写结构，然后两个组件目录都清空一下，路由模块的数组也清空一下</p>
<h3 id="安装和配置Vant组件库"><a href="#安装和配置Vant组件库" class="headerlink" title="安装和配置Vant组件库"></a>安装和配置Vant组件库</h3><p>官网：<a target="_blank" rel="noopener" href="https://vant-contrib.gitee.io/vant/#/zh-CN/">Vant - 轻量、可靠的移动端组件库 (gitee.io)</a></p>
<h4 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h4><p>通过 npm 安装</p>
<p>在现有项目中使用 Vant 时，可以通过 <code>npm</code> 或 <code>yarn</code> 进行安装：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Vue 2 项目，安装 Vant 2：</span></span><br><span class="line">npm i vant -S</span><br><span class="line"></span><br><span class="line"><span class="comment"># Vue 3 项目，安装 Vant 3：</span></span><br><span class="line">npm i vant@next -S</span><br></pre></td></tr></table></figure>

<h4 id="引入"><a href="#引入" class="headerlink" title="引入"></a>引入</h4><p>推荐使用按需引入</p>
<p>按需导入的话，每次使用一个组件，都要导入，然后注册</p>
<p>但是开发中推荐使用全部导入的方式（引入所有组件会增加代码包体积，因此不推荐这种做法），发布的时候我们可以再优化体积</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> Vant <span class="keyword">from</span> <span class="string">&#x27;vant&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;vant/lib/index.css&#x27;</span>;</span><br><span class="line"></span><br><span class="line">Vue.use(Vant);</span><br></pre></td></tr></table></figure>

<h4 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h4><p>按钮例子</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;van-button type=&quot;primary&quot;&gt;主要按钮&lt;/van-button&gt;</span><br><span class="line">&lt;van-button type=&quot;info&quot;&gt;信息按钮&lt;/van-button&gt;</span><br><span class="line">&lt;van-button type=&quot;default&quot;&gt;默认按钮&lt;/van-button&gt;</span><br><span class="line">&lt;van-button type=&quot;warning&quot;&gt;警告按钮&lt;/van-button&gt;</span><br><span class="line">&lt;van-button type=&quot;danger&quot;&gt;危险按钮&lt;/van-button&gt;</span><br></pre></td></tr></table></figure>



<p>放置组件，路由相关的组件放在views文件夹中</p>
<p>新建Home.vue文件夹和User.vue文件夹</p>
<h4 id="使用Tabbar栏"><a href="#使用Tabbar栏" class="headerlink" title="使用Tabbar栏"></a>使用Tabbar栏</h4><p>在App根组件下面放置一个tabbar</p>
<p>点击不同的tabbar，切换不同的页面router-view</p>
<h4 id="基础用法"><a href="#基础用法" class="headerlink" title="基础用法"></a>基础用法</h4><p><code>v-model</code> 默认绑定选中标签的索引值，通过修改 <code>v-model</code> 即可切换选中的标签。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">van-tabbar</span> <span class="attr">v-model</span>=<span class="string">&quot;active&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">van-tabbar-item</span> <span class="attr">icon</span>=<span class="string">&quot;home-o&quot;</span>&gt;</span>标签<span class="tag">&lt;/<span class="name">van-tabbar-item</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">van-tabbar-item</span> <span class="attr">icon</span>=<span class="string">&quot;search&quot;</span>&gt;</span>标签<span class="tag">&lt;/<span class="name">van-tabbar-item</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">van-tabbar-item</span> <span class="attr">icon</span>=<span class="string">&quot;friends-o&quot;</span>&gt;</span>标签<span class="tag">&lt;/<span class="name">van-tabbar-item</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">van-tabbar-item</span> <span class="attr">icon</span>=<span class="string">&quot;setting-o&quot;</span>&gt;</span>标签<span class="tag">&lt;/<span class="name">van-tabbar-item</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">van-tabbar</span>&gt;</span></span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      active: 0,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p><strong>这里把v-model删除，因为什么后面会说</strong></p>
<p>更换ICON图标，侧边栏找到ICON图标部分，找它都有啥值</p>
<p>最终</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- Tabbar区域 --&gt;</span><br><span class="line">&lt;van-tabbar&gt;</span><br><span class="line">  &lt;van-tabbar-item icon=&quot;home-o&quot;&gt;主页&lt;/van-tabbar-item&gt;</span><br><span class="line">  &lt;van-tabbar-item icon=&quot;user-o&quot;&gt;我的&lt;/van-tabbar-item&gt;</span><br><span class="line">&lt;/van-tabbar&gt;</span><br></pre></td></tr></table></figure>

<p>下面的导航栏要是一个router-link点击链接跳转显示组件</p>
<p>这个tabbar组件支持路由模式</p>
<p>标签栏支持路由模式，用于搭配 <code>vue-router</code> 使用。路由模式下会匹配页面路径和标签的 <code>to</code> 属性，并自动选中对应的标签。</p>
<p>写法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- Tabbar区域 --&gt;</span><br><span class="line">&lt;van-tabbar route&gt;</span><br><span class="line">  &lt;van-tabbar-item icon=&quot;home-o&quot; to=&quot;/home&quot;&gt;主页&lt;/van-tabbar-item&gt;</span><br><span class="line">  &lt;van-tabbar-item icon=&quot;user-o&quot; to=&quot;/user&quot;&gt;我的&lt;/van-tabbar-item&gt;</span><br><span class="line">&lt;/van-tabbar&gt;</span><br></pre></td></tr></table></figure>

<p>还需要配置路由模块index.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 路由规则的数组</span></span><br><span class="line"><span class="keyword">const</span> routes = [</span><br><span class="line">  &#123; <span class="attr">path</span>: <span class="string">&#x27;/home&#x27;</span>, <span class="attr">component</span>: Home &#125;,</span><br><span class="line">  &#123; <span class="attr">path</span>: <span class="string">&#x27;/user&#x27;</span>, <span class="attr">component</span>: User &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>在User.vue中声明模板结构</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;user-container&quot;&gt;</span><br><span class="line">    &lt;!-- 用户基本信息面板 --&gt;</span><br><span class="line">    &lt;div class=&quot;user-card&quot;&gt;</span><br><span class="line">      &lt;!-- 用户头像、姓名 --&gt;</span><br><span class="line">      &lt;van-cell&gt;</span><br><span class="line">        &lt;!-- 使用 title 插槽来自定义标题 --&gt;</span><br><span class="line">        &lt;template #icon&gt;</span><br><span class="line">          &lt;img src=&quot;../../assets/logo.png&quot; alt=&quot;&quot; class=&quot;avatar&quot; /&gt;</span><br><span class="line">        &lt;/template&gt;</span><br><span class="line">        &lt;template #title&gt;</span><br><span class="line">          &lt;span class=&quot;username&quot;&gt;用户名&lt;/span&gt;</span><br><span class="line">        &lt;/template&gt;</span><br><span class="line">        &lt;template #label&gt;</span><br><span class="line">          &lt;van-tag color=&quot;#fff&quot; text-color=&quot;#007bff&quot;&gt;申请认证&lt;/van-tag&gt;</span><br><span class="line">        &lt;/template&gt;</span><br><span class="line">      &lt;/van-cell&gt;</span><br><span class="line">      &lt;!-- 动态、关注、粉丝 --&gt;</span><br><span class="line">      &lt;div class=&quot;user-data&quot;&gt;</span><br><span class="line">        &lt;div class=&quot;user-data-item&quot;&gt;</span><br><span class="line">          &lt;span&gt;0&lt;/span&gt;</span><br><span class="line">          &lt;span&gt;动态&lt;/span&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;div class=&quot;user-data-item&quot;&gt;</span><br><span class="line">          &lt;span&gt;0&lt;/span&gt;</span><br><span class="line">          &lt;span&gt;关注&lt;/span&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;div class=&quot;user-data-item&quot;&gt;</span><br><span class="line">          &lt;span&gt;0&lt;/span&gt;</span><br><span class="line">          &lt;span&gt;粉丝&lt;/span&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">    &lt;!-- 操作面板 --&gt;</span><br><span class="line">    &lt;van-cell-group class=&quot;action-card&quot;&gt;</span><br><span class="line">      &lt;van-cell icon=&quot;edit&quot; title=&quot;编辑资料&quot; is-link /&gt;</span><br><span class="line">      &lt;van-cell icon=&quot;chat-o&quot; title=&quot;小思同学&quot; is-link /&gt;</span><br><span class="line">      &lt;van-cell icon=&quot;warning-o&quot; title=&quot;退出登录&quot; is-link /&gt;</span><br><span class="line">    &lt;/van-cell-group&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;User&#x27;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">.user-container &#123;</span><br><span class="line">  .user-card &#123;</span><br><span class="line">    background-color: #007bff;</span><br><span class="line">    color: white;</span><br><span class="line">    padding-top: 20px;</span><br><span class="line">    .van-cell &#123;</span><br><span class="line">      background: #007bff;</span><br><span class="line">      color: white;</span><br><span class="line">      &amp;::after &#123;</span><br><span class="line">        display: none;</span><br><span class="line">      &#125;</span><br><span class="line">      .avatar &#123;</span><br><span class="line">        width: 60px;</span><br><span class="line">        height: 60px;</span><br><span class="line">        background-color: #fff;</span><br><span class="line">        border-radius: 50%;</span><br><span class="line">        margin-right: 10px;</span><br><span class="line">      &#125;</span><br><span class="line">      .username &#123;</span><br><span class="line">        font-size: 14px;</span><br><span class="line">        font-weight: bold;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  .user-data &#123;</span><br><span class="line">    display: flex;</span><br><span class="line">    justify-content: space-evenly;</span><br><span class="line">    align-items: center;</span><br><span class="line">    font-size: 14px;</span><br><span class="line">    padding: 30px 0;</span><br><span class="line">    .user-data-item &#123;</span><br><span class="line">      display: flex;</span><br><span class="line">      flex-direction: column;</span><br><span class="line">      justify-content: center;</span><br><span class="line">      align-items: center;</span><br><span class="line">      width: 33.33%;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h4 id="NavBar导航栏"><a href="#NavBar导航栏" class="headerlink" title="NavBar导航栏"></a>NavBar导航栏</h4><p>基础用法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;van-nav-bar</span><br><span class="line">  title=&quot;标题&quot;</span><br><span class="line">  left-text=&quot;返回&quot;</span><br><span class="line">  right-text=&quot;按钮&quot;</span><br><span class="line">  left-arrow</span><br><span class="line">  @click-left=&quot;onClickLeft&quot;</span><br><span class="line">  @click-right=&quot;onClickRight&quot;</span><br><span class="line">/&gt;</span><br></pre></td></tr></table></figure>

<p>修改出去两端的按钮</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;van-nav-bar title=&quot;标题&quot;/&gt;</span><br></pre></td></tr></table></figure>

<p>这个navbar会随着内容而滚动</p>
<p>所以需要修改，来固定这navbar</p>
<p>加上 “   ： ”   来绑定一个值，而不是字符串</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;van-nav-bar title=&quot;标题&quot; :fixed=&quot;true&quot;/&gt;</span><br></pre></td></tr></table></figure>

<p>默认如果是false值，想要把它改成true的话，并不需要<code>:fixed=&quot;true&quot;</code>这样写</p>
<p>简写：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;van-nav-bar title=&quot;标题&quot; fixed/&gt;</span><br></pre></td></tr></table></figure>



<h4 id="解决navbar和tabbar遮挡内容的问题"><a href="#解决navbar和tabbar遮挡内容的问题" class="headerlink" title="解决navbar和tabbar遮挡内容的问题"></a>解决navbar和tabbar遮挡内容的问题</h4><p>给这内容区域加上边距</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;div class=&quot;home-container&quot;&gt;</span><br><span class="line">    &lt;!-- Navbar区域 --&gt;</span><br><span class="line">    &lt;van-nav-bar title=&quot;标题&quot; fixed/&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">.home-container &#123;</span><br><span class="line">  padding: 46px 0px 50px 0px;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>也可以只给下面加边距，然后navbar区域使用placeholder属性</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;div class=&quot;home-container&quot;&gt;</span><br><span class="line">  &lt;!-- Navbar区域 --&gt;</span><br><span class="line">  &lt;van-nav-bar title=&quot;标题&quot; fixed placeholder/&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">.home-container &#123;</span><br><span class="line">  padding: 0px 0px 50px 0px;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>修改navbar的背景颜色</p>
<p>最经典的方法就是，浏览器调试工具，找到样式属性，修改好了之后，我们在style里面重写一个样式去覆盖</p>
<p>写了不管用的话，加一个 /deep/ 样式穿透</p>
<p> /deep/ 的作用实际上是把  .van-nav-bar_title 加给 home-container  了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">.home-container &#123;</span><br><span class="line">  padding: 46px 0px 50px 0px;</span><br><span class="line">  .van-nav-bar &#123;</span><br><span class="line">    background-color: #007bff;</span><br><span class="line">  &#125;</span><br><span class="line">  /deep/ .van-nav-bar__title &#123;</span><br><span class="line">    color: #ffffff;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>现在的话我们只改了页面内组件的样式，再次使用这个组件还是默认的样式，我们可以通过定制主题的方式来修改统一的样式</p>
<p>这样我们不管在哪使用这个组件都是一样的</p>
<h4 id="文章列表数据接口"><a href="#文章列表数据接口" class="headerlink" title="文章列表数据接口"></a>文章列表数据接口</h4><h5 id="请求方式"><a href="#请求方式" class="headerlink" title="请求方式"></a>请求方式</h5><ul>
<li>GET</li>
</ul>
<h5 id="请求根路径"><a href="#请求根路径" class="headerlink" title="请求根路径"></a>请求根路径</h5><ul>
<li><a target="_blank" rel="noopener" href="https://www.escook.cn/">https://www.escook.cn</a></li>
</ul>
<h5 id="请求URL-地址"><a href="#请求URL-地址" class="headerlink" title="请求URL 地址"></a>请求URL 地址</h5><ul>
<li> /articles</li>
</ul>
<h5 id="查询参数"><a href="#查询参数" class="headerlink" title="查询参数"></a>查询参数</h5><table>
<thead>
<tr>
<th>参数名</th>
<th>数据类型</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>_page</td>
<td>Number</td>
<td>页码值。从 1 开始</td>
</tr>
<tr>
<td>_limit</td>
<td>Number</td>
<td>每页展示的数据条数。</td>
</tr>
</tbody></table>
<h5 id="响应的数据结构"><a href="#响应的数据结构" class="headerlink" title="响应的数据结构"></a>响应的数据结构</h5><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="attr">&quot;art_id&quot;</span>: <span class="string">&quot;8163&quot;</span>,                           <span class="comment">//文章的id</span></span><br><span class="line">        <span class="attr">&quot;title&quot;</span>: <span class="string">&quot;iOS原生混合RN开发最佳实践&quot;</span>,         <span class="comment">//文章的标题</span></span><br><span class="line">        <span class="attr">&quot;aut_id&quot;</span>: <span class="string">&quot;1111&quot;</span>,                           <span class="comment">//作者的id</span></span><br><span class="line">        <span class="attr">&quot;comm_count&quot;</span>: <span class="string">&quot;254&quot;</span>,                        <span class="comment">//文章的评论数量</span></span><br><span class="line">        <span class="attr">&quot;pubdate&quot;</span>: <span class="string">&quot;2019-03-11 09:00:00&quot;</span>,           <span class="comment">//文章的发布日期</span></span><br><span class="line">        <span class="attr">&quot;aut_name&quot;</span>: <span class="string">&quot;黑马先锋&quot;</span>,                      <span class="comment">//作者的名字</span></span><br><span class="line">        <span class="attr">&quot;is_top&quot;</span>: <span class="number">0</span>,                                <span class="comment">//不用管</span></span><br><span class="line">        <span class="attr">&quot;cover&quot;</span>: &#123;                                  <span class="comment">//封面对象，有封面数量和图片路径数组</span></span><br><span class="line">            <span class="attr">&quot;type&quot;</span>: <span class="number">3</span>,</span><br><span class="line">            <span class="attr">&quot;images&quot;</span>: [</span><br><span class="line">                <span class="string">&quot;http://www.liulongbin.top:8000/resources/images/32.jpg&quot;</span>,</span><br><span class="line">                <span class="string">&quot;http://www.liulongbin.top:8000/resources/images/80.jpg&quot;</span>,</span><br><span class="line">                <span class="string">&quot;http://www.liulongbin.top:8000/resources/images/32.jpg&quot;</span></span><br><span class="line">            ]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="attr">&quot;art_id&quot;</span>: <span class="string">&quot;8089&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;title&quot;</span>: <span class="string">&quot;Typescript玩转设计模式 之 创建型模式&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;aut_id&quot;</span>: <span class="string">&quot;1111&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;comm_count&quot;</span>: <span class="string">&quot;24&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;pubdate&quot;</span>: <span class="string">&quot;2019-03-11 09:00:00&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;aut_name&quot;</span>: <span class="string">&quot;黑马先锋&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;is_top&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">&quot;cover&quot;</span>: &#123;</span><br><span class="line">            <span class="attr">&quot;type&quot;</span>: <span class="number">1</span>,</span><br><span class="line">            <span class="attr">&quot;images&quot;</span>: [</span><br><span class="line">                <span class="string">&quot;http://www.liulongbin.top:8000/resources/images/11.jpg&quot;</span></span><br><span class="line">            ]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="attr">&quot;art_id&quot;</span>: <span class="string">&quot;8145&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;title&quot;</span>: <span class="string">&quot;JAVA消息确认机制之ACK模式&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;aut_id&quot;</span>: <span class="string">&quot;1111&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;comm_count&quot;</span>: <span class="string">&quot;99&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;pubdate&quot;</span>: <span class="string">&quot;2019-03-11 09:00:00&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;aut_name&quot;</span>: <span class="string">&quot;黑马先锋&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;is_top&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">&quot;cover&quot;</span>: &#123;</span><br><span class="line">            <span class="attr">&quot;type&quot;</span>: <span class="number">0</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<h5 id="返回参数说明"><a href="#返回参数说明" class="headerlink" title="返回参数说明"></a>返回参数说明</h5><table>
<thead>
<tr>
<th align="left">参数名</th>
<th align="left">类型</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td align="left">art_id</td>
<td align="left">string</td>
<td>文章 id</td>
</tr>
<tr>
<td align="left">title</td>
<td align="left">string</td>
<td>文章标题</td>
</tr>
<tr>
<td align="left">aut_id</td>
<td align="left">string</td>
<td>作者的 id</td>
</tr>
<tr>
<td align="left">comm_count</td>
<td align="left">string</td>
<td>评论数</td>
</tr>
<tr>
<td align="left">pubdate</td>
<td align="left">string</td>
<td>发布日期</td>
</tr>
<tr>
<td align="left">aut_name</td>
<td align="left">string</td>
<td>作者名字</td>
</tr>
<tr>
<td align="left">|- cover</td>
<td align="left">object</td>
<td>文章封面</td>
</tr>
<tr>
<td align="left">|—- type</td>
<td align="left">number</td>
<td>封面的数量，可选值：0、1、3</td>
</tr>
<tr>
<td align="left">|—- images</td>
<td align="left">array</td>
<td>文章封面图片的 URL 数组</td>
</tr>
</tbody></table>
<h4 id="封装request可复用的模块"><a href="#封装request可复用的模块" class="headerlink" title="封装request可复用的模块"></a>封装request可复用的模块</h4><p>安装axios</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i axios -S</span><br></pre></td></tr></table></figure>

<p>可复用的话，就可以创建每个请求路径不一样的baseURL</p>
<p>每个路径不同的模块，我们可以把它共享出去，要调用哪个接口，就引入哪个模块</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> request = axios.create(&#123;</span><br><span class="line">  <span class="attr">baseURL</span>: <span class="string">&#x27;https://www.escook.cn&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> request</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>今后要使用axios，直接导入这个request模块，直接使用请求地址<code>/articles</code>就可以了，不用写完整</p>
<p>接下来Home组件应该一进入页面就应该发请求去拿数据</p>
<h4 id="封装Home组件封装initArticleList方法"><a href="#封装Home组件封装initArticleList方法" class="headerlink" title="封装Home组件封装initArticleList方法"></a>封装Home组件封装initArticleList方法</h4><p>应该在created函数里，调用一个函数来发起请求，这里eslint要求在方法前面加一个空格，如果不需要这个规则，就在eslint里面配置</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;space-before-function-paren&#x27;</span>: [<span class="string">&#x27;error&#x27;</span>, <span class="string">&#x27;never&#x27;</span>]</span><br></pre></td></tr></table></figure>

<p>修改vue的配置文件记得重启一下服务端</p>
<p>封装方法：参数要先定义到data，名字要规范</p>
<p>解构赋值记得用上</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">// 导入request.js</span><br><span class="line">import request from &#x27;@/utils/request&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;Home&#x27;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 页码值</span><br><span class="line">      page: 1,</span><br><span class="line">      // 每页显示多少条数据</span><br><span class="line">      limit: 10</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 发起get请求获取文章的数据,返回是一个promise对象,所以加上await和async</span><br><span class="line">    async initArticleList() &#123;</span><br><span class="line">      // 封装获取文章列表数据的方法,url: /articles</span><br><span class="line">      // 参数: _page页码, _limit条数</span><br><span class="line">      // 解构赋值</span><br><span class="line">      const &#123; data: res &#125; = await request.get(&#x27;/articles&#x27;, &#123;</span><br><span class="line">        // 请求参数</span><br><span class="line">        params: &#123;</span><br><span class="line">          _page: this.page,</span><br><span class="line">          _limit: this.limit</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line"></span><br><span class="line">      console.log(res)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initArticleList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<p>如果另一个页面我的，进来也需要发起请求拿到数据呢</p>
<p>如果三四个页面都需要调同一个接口拿数据呢</p>
<p>请求回来是一个Promise实例对象，只要能拿到这个对象就能拿到数据了，所以这部分的代码可以复用起来</p>
<p><strong>在src目录下，新建文件夹叫api</strong></p>
<p><strong>里面新建articleAPI.js文件</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 文章相关的API接口,都封装到这个模块里</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 向外按需导出一个函数</span></span><br><span class="line"><span class="keyword">import</span> request <span class="keyword">from</span> <span class="string">&#x27;@/utils/request&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> getArticleListAPI = <span class="function"><span class="keyword">function</span>(<span class="params">_page, _limit</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> request.get(<span class="string">&#x27;/articles&#x27;</span>, &#123;</span><br><span class="line">    <span class="comment">// 请求参数</span></span><br><span class="line">    <span class="attr">params</span>: &#123;</span><br><span class="line">      <span class="comment">// 属性值和属性名一样可以简写</span></span><br><span class="line">      _page,</span><br><span class="line">      _limit</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果要在User.vue里面发请求，代码复用后的写法</p>
<p>Promise对象需要加上await，方法体上加上async</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">import &#123; getArticleListAPI &#125; from &#x27;@/api/articleAPI&#x27;</span><br><span class="line"></span><br><span class="line">// const result = getArticleListAPI(1, 5)</span><br><span class="line">// console.log(result)</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;User&#x27;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      page: 1,</span><br><span class="line">      limit: 5</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    async initArticleList() &#123;</span><br><span class="line">      const &#123; data: res &#125; = await getArticleListAPI(this.page, this.limit)</span><br><span class="line">      console.log(res)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initArticleList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>把Home.vue也改成这样的写法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">import &#123; getArticleListAPI &#125; from &#x27;@/api/articleAPI&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;Home&#x27;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 页码值</span><br><span class="line">      page: 1,</span><br><span class="line">      // 每页显示多少条数据</span><br><span class="line">      limit: 10</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 发起get请求获取文章的数据,返回是一个promise对象,所以加上await和async</span><br><span class="line">    async initArticleList() &#123;</span><br><span class="line">      // 封装获取文章列表数据的方法,url: /articles</span><br><span class="line">      // 参数: _page页码, _limit条数</span><br><span class="line">      // 解构赋值</span><br><span class="line">      const &#123; data: res &#125; = await getArticleListAPI(this.page, this.limit)</span><br><span class="line">      console.log(res)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initArticleList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>按需导入方法使用</p>
<p>接下来需要渲染拿到的数据，在Home.vue组件中</p>
<p>定义存放的数据，默认是空</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">artlist: []</span><br></pre></td></tr></table></figure>

<p>在方法中赋值</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.artlist = res</span><br></pre></td></tr></table></figure>



<h4 id="封装文章组件"><a href="#封装文章组件" class="headerlink" title="封装文章组件"></a>封装文章组件</h4><p>不是有关路由的组件放在compontent文件夹里面</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;articleinfo-container&quot;&gt;</span><br><span class="line">    ArticleInfo组件</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;ArticleInfo&#x27;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>Home.vue部分代码</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;ArticleInfo v-for=&quot;item in artlist&quot; :key=&quot;item.id&quot;&gt;&lt;/ArticleInfo&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import ArticleInfo from &#x27;@/components/Article/ArticleInfo&#x27;</span><br><span class="line">import &#123; getArticleListAPI &#125; from &#x27;@/api/articleAPI&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    ArticleInfo</span><br><span class="line">  &#125;,</span><br></pre></td></tr></table></figure>



<p>重写补完articleInfo.vue中的代码</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;van-cell&gt;</span><br><span class="line">      &lt;!-- 标题区域的插槽 --&gt;</span><br><span class="line">      &lt;template #title&gt;</span><br><span class="line">        &lt;div class=&quot;title-box&quot;&gt;</span><br><span class="line">          &lt;!-- 标题 --&gt;</span><br><span class="line">          &lt;span&gt;文章的标题噢&lt;/span&gt;</span><br><span class="line">          &lt;!-- 单张图片 --&gt;</span><br><span class="line">          &lt;img src=&quot;https://www.escook.cn/vuebase/pics/1.png&quot; alt=&quot;&quot; class=&quot;thumb&quot;&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;!-- 三张图片 --&gt;</span><br><span class="line">        &lt;div class=&quot;thumb-box&quot;&gt;</span><br><span class="line">          &lt;img src=&quot;https://www.escook.cn/vuebase/pics/2.png&quot; alt=&quot;&quot; class=&quot;thumb&quot;&gt;</span><br><span class="line">          &lt;img src=&quot;https://www.escook.cn/vuebase/pics/2.png&quot; alt=&quot;&quot; class=&quot;thumb&quot;&gt;</span><br><span class="line">          &lt;img src=&quot;https://www.escook.cn/vuebase/pics/2.png&quot; alt=&quot;&quot; class=&quot;thumb&quot;&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">      &lt;!-- label 区域的插槽 --&gt;</span><br><span class="line">      &lt;template #label&gt;</span><br><span class="line">        &lt;div class=&quot;label-box&quot;&gt;</span><br><span class="line">          &lt;span&gt;作者 &amp;nbsp;&amp;nbsp; 0评论 &amp;nbsp;&amp;nbsp; 发布日期&lt;/span&gt;</span><br><span class="line">          &lt;!-- 关闭按钮 --&gt;</span><br><span class="line">          &lt;van-icon name=&quot;cross&quot; /&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">    &lt;/van-cell&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;ArticleInfo&#x27;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;less&quot; scoped&gt;</span><br><span class="line">.label-box &#123;</span><br><span class="line">  display: flex;</span><br><span class="line">  justify-content: space-between;</span><br><span class="line">  align-items: center;</span><br><span class="line">&#125;</span><br><span class="line">.thumb &#123;</span><br><span class="line">  // 矩形黄金比例：0.618</span><br><span class="line">  width: 113px;</span><br><span class="line">  height: 70px;</span><br><span class="line">  background-color: #f8f8f8;</span><br><span class="line">  object-fit: cover;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.title-box &#123;</span><br><span class="line">  display: flex;</span><br><span class="line">  justify-content: space-between;</span><br><span class="line">  align-items: flex-start;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.thumb-box &#123;</span><br><span class="line">  display: flex;</span><br><span class="line">  justify-content: space-between;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>把模板改成填充数据的样式</p>
<p>又要用到props传递参数了</p>
<p>ArticleInfo.vue代码</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;van-cell&gt;</span><br><span class="line">      &lt;!-- 标题区域的插槽 --&gt;</span><br><span class="line">      &lt;template #title&gt;</span><br><span class="line">        &lt;div class=&quot;title-box&quot;&gt;</span><br><span class="line">          &lt;!-- 标题 --&gt;</span><br><span class="line">          &lt;span&gt;双大括号 title 双大括号&lt;/span&gt;</span><br><span class="line">          &lt;!-- cover的值是1和3，分别有两种显示效果，既不等于1也不等3，两种都看不到 --&gt;</span><br><span class="line">          &lt;!-- 单张图片 --&gt;</span><br><span class="line">          &lt;img :src=&quot;cover.images[0]&quot; alt=&quot;&quot; class=&quot;thumb&quot; v-if=&quot;cover.type === 1&quot;&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;!-- 三张图片 --&gt;</span><br><span class="line">        &lt;!-- 不能v-else了，因为不是平级的 --&gt;</span><br><span class="line">        &lt;div class=&quot;thumb-box&quot; v-if=&quot;cover.type === 3&quot;&gt;</span><br><span class="line">          &lt;img :src=&quot;item&quot; alt=&quot;&quot; class=&quot;thumb&quot; v-for=&quot;(item, i) in cover.images&quot; :key=&quot;i&quot;&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">      &lt;!-- label 区域的插槽 --&gt;</span><br><span class="line">      &lt;template #label&gt;</span><br><span class="line">        &lt;div class=&quot;label-box&quot;&gt;</span><br><span class="line">          &lt;span&gt;作者 双大括号 author 双大括号 &amp;nbsp;&amp;nbsp; 双大括号 cmtCount 双大括号 评论 &amp;nbsp;&amp;nbsp; 发布日期 双大括号 time 双大括号&lt;/span&gt;</span><br><span class="line">          &lt;!-- 关闭按钮 --&gt;</span><br><span class="line">          &lt;van-icon name=&quot;cross&quot; /&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">    &lt;/van-cell&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;ArticleInfo&#x27;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 文章标题</span><br><span class="line">    title: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 作者名字</span><br><span class="line">    author: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 评论数量,定义多个类型</span><br><span class="line">    cmtCount: &#123;</span><br><span class="line">      type: [Number, String],</span><br><span class="line">      default: 0</span><br><span class="line">    &#125;,</span><br><span class="line">    time: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 图像,如果默认值是空对象必须加一个function</span><br><span class="line">    // 对象默认值必须从一个工厂函数中获取</span><br><span class="line">    cover: &#123;</span><br><span class="line">      type: Object,</span><br><span class="line">      default: function() &#123;</span><br><span class="line">        return &#123; type: 0 &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在Home.vue中使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;ArticleInfo</span><br><span class="line">    v-for=&quot;item in artlist&quot;</span><br><span class="line">    :key=&quot;item.id&quot;</span><br><span class="line">    :title=&quot;item.title&quot;</span><br><span class="line">    :author=&quot;item.aut_name&quot;</span><br><span class="line">    :cmt-count=&quot;item.comm_count&quot;</span><br><span class="line">    :time=&quot;item.pubdate&quot;</span><br><span class="line">    :cover=&quot;item.cover&quot;</span><br><span class="line">&gt;</span><br><span class="line">&lt;/ArticleInfo&gt;</span><br></pre></td></tr></table></figure>



<h4 id="上拉加载更多数据"><a href="#上拉加载更多数据" class="headerlink" title="上拉加载更多数据"></a>上拉加载更多数据</h4><h5 id="Vant的List组件"><a href="#Vant的List组件" class="headerlink" title="Vant的List组件"></a>Vant的List组件</h5><p><a target="_blank" rel="noopener" href="https://vant-contrib.gitee.io/vant/#/zh-CN/list">Vant - 轻量、可靠的移动端组件库 (gitee.io)</a></p>
<p>瀑布流滚动加载，用于展示长列表，当列表即将滚动到底部时，会触发事件并加载更多列表项。</p>
<p><strong>基本使用</strong></p>
<p>List 组件通过 <code>loading</code> 和 <code>finished</code> 两个变量控制加载状态，当组件滚动到底部时，会触发 <code>load</code> 事件并将 <code>loading</code> 设置成 <code>true</code>。此时可以发起异步操作并更新数据，数据更新完毕后，将 <code>loading</code> 设置成 <code>false</code> 即可。若数据已全部加载完毕，则直接将 <code>finished</code> 设置成 <code>true</code> 即可。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">van-list</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-model</span>=<span class="string">&quot;loading&quot;</span></span></span><br><span class="line"><span class="tag">  <span class="attr">:finished</span>=<span class="string">&quot;finished&quot;</span></span></span><br><span class="line"><span class="tag">  <span class="attr">finished-text</span>=<span class="string">&quot;没有更多了&quot;</span></span></span><br><span class="line"><span class="tag">  @<span class="attr">load</span>=<span class="string">&quot;onLoad&quot;</span></span></span><br><span class="line"><span class="tag">&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">van-cell</span> <span class="attr">v-for</span>=<span class="string">&quot;item in list&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;item&quot;</span> <span class="attr">:title</span>=<span class="string">&quot;item&quot;</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">van-list</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">      <span class="attr">list</span>: [],</span></span><br><span class="line"><span class="javascript">      <span class="attr">loading</span>: <span class="literal">false</span>,</span></span><br><span class="line"><span class="javascript">      <span class="attr">finished</span>: <span class="literal">false</span>,</span></span><br><span class="line"><span class="javascript">    &#125;;</span></span><br><span class="line"><span class="javascript">  &#125;,</span></span><br><span class="line"><span class="javascript">  <span class="attr">methods</span>: &#123;</span></span><br><span class="line"><span class="javascript">    <span class="function"><span class="title">onLoad</span>(<span class="params"></span>)</span> &#123;</span></span><br><span class="line"><span class="javascript">      <span class="comment">// 异步更新数据</span></span></span><br><span class="line"><span class="javascript">      <span class="comment">// setTimeout 仅做示例，真实场景中一般为 ajax 请求</span></span></span><br><span class="line"><span class="javascript">      <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.list.push(<span class="built_in">this</span>.list.length + <span class="number">1</span>);</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 加载状态结束</span></span></span><br><span class="line"><span class="javascript">        <span class="built_in">this</span>.loading = <span class="literal">false</span>;</span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 数据全部加载完成</span></span></span><br><span class="line"><span class="javascript">        <span class="keyword">if</span> (<span class="built_in">this</span>.list.length &gt;= <span class="number">40</span>) &#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">this</span>.finished = <span class="literal">true</span>;</span></span><br><span class="line"><span class="javascript">        &#125;</span></span><br><span class="line"><span class="javascript">      &#125;, <span class="number">1000</span>);</span></span><br><span class="line"><span class="javascript">    &#125;,</span></span><br><span class="line"><span class="javascript">  &#125;,</span></span><br><span class="line"><span class="javascript">&#125;;</span></span><br><span class="line"><span class="javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>复制到我们要使用的list页面上，Home.vue</p>
<p>把要遍历的数据和组件包裹起来</p>
<p><strong>完整代码和注释</strong></p>
<h5 id="上拉加载"><a href="#上拉加载" class="headerlink" title="上拉加载"></a>上拉加载</h5><p>Home.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;home-container&quot;&gt;</span><br><span class="line">    &lt;!-- Navbar区域 --&gt;</span><br><span class="line">    &lt;van-nav-bar title=&quot;今日头条&quot; fixed/&gt;</span><br><span class="line">    &lt;!-- 瀑布流滚动加载，用于展示长列表 --&gt;</span><br><span class="line">    &lt;!-- List 组件通过 loading 和 finished 两个变量控制加载状态，当组件滚动到底部时，</span><br><span class="line">    会触发 load 事件并将 loading 设置成 true。此时可以发起异步操作并更新数据，</span><br><span class="line">    数据更新完毕后，将 loading 设置成 false 即可。若数据已全部加载完毕，</span><br><span class="line">    则直接将 finished 设置成 true 即可。--&gt;</span><br><span class="line">    &lt;van-list</span><br><span class="line">        v-model=&quot;loading&quot;</span><br><span class="line">        :finished=&quot;finished&quot;</span><br><span class="line">        finished-text=&quot;没有更多了&quot;</span><br><span class="line">        @load=&quot;onLoad&quot;</span><br><span class="line">    &gt;</span><br><span class="line">    &lt;!-- 导入，注册，使用ArticleInfo组件 --&gt;</span><br><span class="line">    &lt;!-- 有大写字母的可以写成连字符格式 --&gt;</span><br><span class="line">      &lt;ArticleInfo</span><br><span class="line">        v-for=&quot;item in artlist&quot;</span><br><span class="line">        :key=&quot;item.id&quot;</span><br><span class="line">        :title=&quot;item.title&quot;</span><br><span class="line">        :author=&quot;item.aut_name&quot;</span><br><span class="line">        :cmt-count=&quot;item.comm_count&quot;</span><br><span class="line">        :time=&quot;item.pubdate&quot;</span><br><span class="line">        :cover=&quot;item.cover&quot;</span><br><span class="line">      &gt;&lt;/ArticleInfo&gt;</span><br><span class="line">    &lt;/van-list&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import ArticleInfo from &#x27;@/components/Article/ArticleInfo&#x27;</span><br><span class="line">import &#123; getArticleListAPI &#125; from &#x27;@/api/articleAPI&#x27;</span><br><span class="line">export default &#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    ArticleInfo</span><br><span class="line">  &#125;,</span><br><span class="line">  name: &#x27;Home&#x27;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 页码值</span><br><span class="line">      page: 1,</span><br><span class="line">      // 每页显示多少条数据</span><br><span class="line">      limit: 10,</span><br><span class="line">      //  存放文章的数组默认空</span><br><span class="line">      artlist: [],</span><br><span class="line">      // 是否正在加载下一页，如果为true不会触发onload事件</span><br><span class="line">      // 请求数据回来记得把loading改为true</span><br><span class="line">      // 改成默认是true吧，不然默认一进来就触发一次</span><br><span class="line">      loading: true,</span><br><span class="line">      // 所有数据是否加载完毕了，没有数据了把finished改成true</span><br><span class="line">      finished: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 发起get请求获取文章的数据,返回是一个promise对象,所以加上await和async</span><br><span class="line">    async initArticleList() &#123;</span><br><span class="line">      // 封装获取文章列表数据的方法,url: /articles</span><br><span class="line">      // 参数: _page页码, _limit条数</span><br><span class="line">      // 解构赋值</span><br><span class="line">      const &#123; data: res &#125; = await getArticleListAPI(this.page, this.limit)</span><br><span class="line">      // this.artlist = [新数据在前, 旧数据在后]</span><br><span class="line">      this.artlist = [...this.artlist, ...res]</span><br><span class="line">      // 默认loading是true，有数据了之后可以改回false才能下次触发onload</span><br><span class="line">      this.loading = false</span><br><span class="line">      console.log(res)</span><br><span class="line">    &#125;,</span><br><span class="line">    // 下滑会触发onload事件，发起请求拿到新的数据</span><br><span class="line">    onLoad() &#123;</span><br><span class="line">      // 1.页码值加1</span><br><span class="line">      this.page++</span><br><span class="line">      // 2.重新请求接口获取数据,写到这里发现旧10条数据被新10条数据覆盖了，应该是加上才对的</span><br><span class="line">      // 改造过后的init方法</span><br><span class="line">      this.initArticleList()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initArticleList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>如果没有更多数据了，应该把finished改成true</strong></p>
<p><strong>最后在initArticleListf方法内最后部分判断一下</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="title">initArticleList</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">      <span class="comment">// 封装获取文章列表数据的方法,url: /articles</span></span><br><span class="line">      <span class="comment">// 参数: _page页码, _limit条数</span></span><br><span class="line">      <span class="comment">// 解构赋值</span></span><br><span class="line">      <span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> getArticleListAPI(<span class="built_in">this</span>.page, <span class="built_in">this</span>.limit)</span><br><span class="line">      <span class="comment">// this.artlist = [新数据在前, 旧数据在后]</span></span><br><span class="line">      <span class="built_in">this</span>.artlist = [...this.artlist, ...res]</span><br><span class="line">      <span class="comment">// 默认loading是true，有数据了之后可以改回false才能下次触发onload</span></span><br><span class="line">      <span class="built_in">this</span>.loading = <span class="literal">false</span></span><br><span class="line">      <span class="comment">// 没有数据了，就把finished改为true</span></span><br><span class="line">      <span class="keyword">if</span> (res.length === <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="built_in">this</span>.finished = <span class="literal">true</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<h4 id="下拉刷新数据"><a href="#下拉刷新数据" class="headerlink" title="下拉刷新数据"></a>下拉刷新数据</h4><p>实现下拉列表刷新数据的效果</p>
<p>List 组件可以与 <a target="_blank" rel="noopener" href="https://vant-contrib.gitee.io/vant/#/zh-CN/pull-refresh">PullRefresh</a> 组件结合使用，实现下拉刷新的效果。</p>
<p>用于提供下拉刷新的交互操作，业务：无论是上拉还是下拉都应该加载的是下一页数据</p>
<p><strong>基础用法：</strong></p>
<p>下拉刷新时会触发 <code>refresh</code> 事件，在事件的回调函数中可以进行同步或异步操作，操作完成后将 <code>v-model</code> 设置为 <code>false</code>，表示加载完成。</p>
<p><strong>init函数请求数据，如果是上拉刷新数据，应该是拼接到后面，下拉刷新，应该是拼接在上面</strong></p>
<p>要改造一下init方法，加上一个boolean值，判断一下</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;home-container&quot;&gt;</span><br><span class="line">    &lt;!-- Navbar区域 --&gt;</span><br><span class="line">    &lt;van-nav-bar title=&quot;今日头条&quot; fixed/&gt;</span><br><span class="line"></span><br><span class="line">    &lt;!-- disabled属性是：是否禁用下拉刷新，默认值是false --&gt;</span><br><span class="line">    &lt;van-pull-refresh v-model=&quot;isLoading&quot; :disabled=&quot;finished&quot; @refresh=&quot;onRefresh&quot;&gt;</span><br><span class="line">    &lt;!-- 瀑布流滚动加载，用于展示长列表 --&gt;</span><br><span class="line">    &lt;!-- List 组件通过 loading 和 finished 两个变量控制加载状态，当组件滚动到底部时，</span><br><span class="line">    会触发 load 事件并将 loading 设置成 true。此时可以发起异步操作并更新数据，</span><br><span class="line">    数据更新完毕后，将 loading 设置成 false 即可。若数据已全部加载完毕，</span><br><span class="line">    则直接将 finished 设置成 true 即可。--&gt;</span><br><span class="line">      &lt;van-list</span><br><span class="line">        v-model=&quot;loading&quot;</span><br><span class="line">        :finished=&quot;finished&quot;</span><br><span class="line">        finished-text=&quot;没有更多了&quot;</span><br><span class="line">        @load=&quot;onLoad&quot;</span><br><span class="line">      &gt;</span><br><span class="line">    &lt;!-- 导入，注册，使用ArticleInfo组件 --&gt;</span><br><span class="line">    &lt;!-- 有大写字母的可以写成连字符格式 --&gt;</span><br><span class="line">        &lt;ArticleInfo</span><br><span class="line">        v-for=&quot;item in artlist&quot;</span><br><span class="line">        :key=&quot;item.id&quot;</span><br><span class="line">        :title=&quot;item.title&quot;</span><br><span class="line">        :author=&quot;item.aut_name&quot;</span><br><span class="line">        :cmt-count=&quot;item.comm_count&quot;</span><br><span class="line">        :time=&quot;item.pubdate&quot;</span><br><span class="line">        :cover=&quot;item.cover&quot;</span><br><span class="line">        &gt;</span><br><span class="line">        &lt;/ArticleInfo&gt;</span><br><span class="line">      &lt;/van-list&gt;</span><br><span class="line">    &lt;/van-pull-refresh&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import ArticleInfo from &#x27;@/components/Article/ArticleInfo&#x27;</span><br><span class="line">import &#123; getArticleListAPI &#125; from &#x27;@/api/articleAPI&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    ArticleInfo</span><br><span class="line">  &#125;,</span><br><span class="line">  name: &#x27;Home&#x27;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      // 页码值</span><br><span class="line">      page: 1,</span><br><span class="line">      // 每页显示多少条数据</span><br><span class="line">      limit: 10,</span><br><span class="line">      //  存放文章的数组默认空</span><br><span class="line">      artlist: [],</span><br><span class="line">      // 是否正在加载下一页，如果为true不会触发onload事件</span><br><span class="line">      // 请求数据回来记得把loading改为true</span><br><span class="line">      // 改成默认是true吧，不然默认一进来就触发一次</span><br><span class="line">      loading: true,</span><br><span class="line">      // 所有数据是否加载完毕了，没有数据了把finished改成true</span><br><span class="line">      finished: false,</span><br><span class="line">      // 是否正在下拉刷新</span><br><span class="line">      isLoading: true</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 发起get请求获取文章的数据,返回是一个promise对象,所以加上await和async</span><br><span class="line">    // 判断方法用来干什么的,根据值来判断是尾部拼接还是头部拼接,只有下拉刷新传参数，其他不传就走下面</span><br><span class="line">    async initArticleList(isRrefresh) &#123;</span><br><span class="line">      // 封装获取文章列表数据的方法,url: /articles</span><br><span class="line">      // 参数: _page页码, _limit条数</span><br><span class="line">      // 解构赋值</span><br><span class="line">      const &#123; data: res &#125; = await getArticleListAPI(this.page, this.limit)</span><br><span class="line"></span><br><span class="line">      if (isRrefresh) &#123;</span><br><span class="line">        // 下拉刷新,新数据在前,旧数据在后</span><br><span class="line">        this.artlist = [...res, ...this.artlist]</span><br><span class="line">        // 修改为false,下次才能再次触发</span><br><span class="line">        this.isLoading = false</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        // 上拉加载更多数据,新数据在后,旧数据在前</span><br><span class="line">        // this.artlist = [新数据在前, 旧数据在后]</span><br><span class="line">        this.artlist = [...this.artlist, ...res]</span><br><span class="line">        // 默认loading是true，有数据了之后可以改回false才能下次触发onload</span><br><span class="line">        this.loading = false</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      // 没有数据了，就把finished改为true</span><br><span class="line">      if (res.length === 0) &#123;</span><br><span class="line">        this.finished = true</span><br><span class="line">      &#125;</span><br><span class="line">      console.log(res)</span><br><span class="line">    &#125;,</span><br><span class="line">    // 下滑会触发onload事件，发起请求拿到新的数据</span><br><span class="line">    onLoad() &#123;</span><br><span class="line">      // 1.页码值加1</span><br><span class="line">      this.page++</span><br><span class="line">      // 2.重新请求接口获取数据,写到这里发现旧10条数据被新10条数据覆盖了，应该是加上才对的</span><br><span class="line">      // 改造过后的init方法</span><br><span class="line">      this.initArticleList()</span><br><span class="line">    &#125;,</span><br><span class="line">    onRefresh() &#123;</span><br><span class="line">      // 1.让页码值加1</span><br><span class="line">      this.page++</span><br><span class="line">      // 2.重新请求数据</span><br><span class="line">      this.initArticleList(true)</span><br><span class="line">      console.log(&#x27;触发onrefresh函数&#x27;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initArticleList()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h4 id="Vant定制主题"><a href="#Vant定制主题" class="headerlink" title="Vant定制主题"></a>Vant定制主题</h4><p>之前使用navbar后，还要通过样式来修改字体颜色和背景颜色</p>
<p>在别的页面使用navbar也是一样的，定制主题可以让组件在所有的页面样式一致</p>
<p><strong>Vant 提供了一套默认主题，CSS 命名采用 BEM 的风格，方便使用者覆盖样式。如果你想完全替换主题色或者其他样式，可以按照本文档进行主题定制。</strong></p>
<p><strong>Vant 使用了 <a target="_blank" rel="noopener" href="http://lesscss.org/">Less</a> 对样式进行预处理，并内置了一些样式变量，通过替换样式变量即可定制你自己需要的主题。</strong></p>
<p>查看navabr文档，发现提供了less变量</p>
<h5 id="步骤一-引入样式源文件"><a href="#步骤一-引入样式源文件" class="headerlink" title="步骤一 引入样式源文件"></a>步骤一 引入样式源文件</h5><p>定制主题时，需要引入组件对应的 Less 样式文件，支持按需引入和手动引入两种方式。</p>
<p>在main.js文件中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&#x27;vant/lib/index.less&#x27;</span></span><br></pre></td></tr></table></figure>

<p>如果 vue-cli 搭建的项目，可以在 <code>vue.config.js</code> 中进行配置。</p>
<p>项目根目录创建vue.config.js文件，<code>这个文件是vue-cli对项目进行全局配置的文件</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vue.config.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">css</span>: &#123;</span><br><span class="line">    <span class="attr">loaderOptions</span>: &#123;</span><br><span class="line">      <span class="attr">less</span>: &#123;</span><br><span class="line">        <span class="comment">// 若 less-loader 版本小于 6.0，请移除 lessOptions 这一级，直接配置选项。</span></span><br><span class="line">        <span class="attr">lessOptions</span>: &#123;</span><br><span class="line">          <span class="attr">modifyVars</span>: &#123;</span><br><span class="line">            <span class="comment">// 直接覆盖变量</span></span><br><span class="line">            <span class="string">&#x27;text-color&#x27;</span>: <span class="string">&#x27;#111&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;border-color&#x27;</span>: <span class="string">&#x27;#eee&#x27;</span>,</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>每次修改配置文件都要重启服务端，不太方便</p>
<p>使用下面注释掉的less方法，通过less文件的覆盖来定制主题</p>
<p>less能够在样式中定义变量</p>
<p>在src新建<strong>theme.less</strong>文件</p>
<p>代码如下：</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在这个文件中可以覆盖Vant官方的变量</span></span><br><span class="line"><span class="variable">@blue:</span> <span class="number">#007bff</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 覆盖less的默认样式</span></span><br><span class="line"><span class="variable">@nav-bar-background-color:</span> <span class="variable">@blue</span>;</span><br></pre></td></tr></table></figure>

<p>修改配置文件 <code>vue.config.js</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vue.config.js是vue-cli创建的项目配置文件</span></span><br><span class="line"><span class="comment">// 在vue.config.js这个配置文件中，可以对项目进行打包，构建全局的配置</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// webpack在进行打包的时候，底层用到了node.js</span></span><br><span class="line"><span class="comment">// 因此，vue.config.js配置文件中，可以导入并使用node.js中的核心模块</span></span><br><span class="line"><span class="comment">// __dirname表示这个文件所在的目录</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> themePath = path.join(__dirname, <span class="string">&#x27;./src/theme.less&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">css</span>: &#123;</span><br><span class="line">    <span class="attr">loaderOptions</span>: &#123;</span><br><span class="line">      <span class="attr">less</span>: &#123;</span><br><span class="line">        <span class="attr">modifyVars</span>: &#123;</span><br><span class="line">          <span class="comment">// 直接覆盖变量,要重启生效</span></span><br><span class="line">          <span class="comment">// &#x27;nav-bar-background-color&#x27;: &#x27;blue&#x27;,</span></span><br><span class="line">          <span class="comment">// &#x27;nav-bar-text-color&#x27;: &#x27;white&#x27;</span></span><br><span class="line">          <span class="comment">// 或者可以通过 less 文件覆盖（文件路径为绝对路径）, &#x27;../这种是相对路径’，从盘符开始的就是绝对路径</span></span><br><span class="line">          <span class="comment">// 格式是模板字符串</span></span><br><span class="line">          <span class="attr">hack</span>: <span class="string">`true; @import &quot;<span class="subst">$&#123;themePath &#125;</span>&quot;;`</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="项目打包"><a href="#项目打包" class="headerlink" title="项目打包"></a>项目打包</h4><p>默认运行<code>npm run build</code>，打包项目</p>
<p>生成了dist文件夹，里面运行index.html是看不到文件的，只有通过放在服务器上通过http协议访问才能打开的</p>
<p>普通双击打开的文件是file协议的</p>
<p>vue-cli文档：<a target="_blank" rel="noopener" href="https://cli.vuejs.org/zh/config/#publicpath">配置参考 | Vue CLI (vuejs.org)</a></p>
<p><strong>publicPath</strong></p>
<p>默认情况下，Vue CLI 会假设你的应用是被部署在一个域名的根路径上，例如 <code>https://www.my-app.com/</code>。如果应用被部署在一个子路径上，你就需要用这个选项指定这个子路径。例如，如果你的应用被部署在 <code>https://www.my-app.com/my-app/</code>，则设置 <code>publicPath</code> 为 <code>/my-app/</code>。</p>
<p>这个值也可以被设置为空字符串 (<code>&#39;&#39;</code>) 或是相对路径 (<code>&#39;./&#39;</code>)，这样所有的资源都会被链接为相对路径，这样打出来的包可以被部署在任意路径，也可以用在类似 Cordova hybrid 应用的文件系统中。</p>
<p><strong>在vue.config.js文件中的代码片段</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  <span class="attr">publicPath</span>: <span class="string">&#x27;./&#x27;</span>,</span><br><span class="line">  <span class="attr">css</span>: &#123;</span><br></pre></td></tr></table></figure>

<p>还比如devServer选项能修改端口</p>
<h4 id="项目案例的小修改"><a href="#项目案例的小修改" class="headerlink" title="项目案例的小修改"></a>项目案例的小修改</h4><p>当我们滑动信息的时候，切换其他页面，有时需要去记录下页面的滚动位置，方便用户回来继续浏览信息</p>
<p>实现记录滚动条位置的操作，我们需要用到很多技术</p>
<p>比如：缓存，加上了不会销毁组件了</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;keep-alive include=&quot;Home&quot;&gt;</span><br><span class="line">	&lt;router-view&gt;&lt;/router-view&gt;</span><br><span class="line">&lt;/keep-alive&gt;</span><br></pre></td></tr></table></figure>

<p>还有在路由模块index.js中加上了元信息，为了记录位置</p>
<p>return出去的位置就是会停在那个位置上</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">routes: [</span><br><span class="line">  &#123; <span class="attr">path</span>: <span class="string">&#x27;/&#x27;</span>, <span class="attr">component</span>: Home, <span class="attr">meta</span>: &#123; <span class="attr">isRecord</span>:<span class="literal">true</span>, <span class="attr">top</span>: <span class="number">0</span> &#125; &#125;,</span><br><span class="line">  &#123; <span class="attr">path</span>: <span class="string">&#x27;/user&#x27;</span>, <span class="attr">component</span>: User &#125;</span><br><span class="line">]，</span><br><span class="line"><span class="function"><span class="title">scrollBehavior</span>(<span class="params">to, <span class="keyword">from</span>, savePosition</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span>(savedPosition) &#123;</span><br><span class="line">        <span class="keyword">return</span> savePosition</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123; <span class="attr">x</span>:<span class="number">0</span>, <span class="attr">y</span>: to.meta.top || <span class="number">0</span> &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在Home.vue上加上一个事件监听</p>
<p>当被缓存时移除事件监听</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">activated</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	fn = <span class="built_in">this</span>.recordTopHandler()</span><br><span class="line">	<span class="built_in">window</span>.addEventListener(<span class="string">&#x27;scroll&#x27;</span>, fn)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 当被缓存时移除事件监听</span></span><br><span class="line"><span class="function"><span class="title">deactivated</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">	<span class="built_in">window</span>.removeEventListener(<span class="string">&#x27;scroll&#x27;</span>, fn)</span><br><span class="line">&#125;</span><br><span class="line"><span class="attr">methods</span>: &#123;</span><br><span class="line">	<span class="function"><span class="title">recordTopHandler</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> _.debounce(</span><br><span class="line">			<span class="function">() =&gt;</span> &#123;</span><br><span class="line">				<span class="built_in">this</span>.$route.meta.top = <span class="built_in">window</span>.scrollY</span><br><span class="line">			&#125;,</span><br><span class="line">			<span class="number">50</span>,</span><br><span class="line">			&#123; <span class="attr">trailing</span>: <span class="literal">true</span> &#125;</span><br><span class="line">		)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个下划线是什么呢</p>
<p>Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库</p>
<p>lodash提供了很多函数，比如防抖，节流，数组的一系列函数，操作对象的一系列函数，对象的深拷贝和浅拷贝</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import _ from &#x27;lodash&#x27;</span><br><span class="line">let fn = null</span><br></pre></td></tr></table></figure>



<h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><ul>
<li>如何使用vue-cli创建和开发工程化的vue项目</li>
<li>能够熟练运用组件化的开发思想，进行企业级的项目开发</li>
<li>能够熟练运用指令，侦听器，插槽，声明周期，组件通讯等技术</li>
<li>在vue项目中如何封装和使用axios来请求后端的API接口</li>
<li>能够熟练使用vue-router实现单页面应用的开发</li>
<li>能过够在项目中使用Vant组件库</li>
<li>熟练使用vue-devtool来调试项目</li>
</ul>
<h3 id="ES6模块化和异步编程"><a href="#ES6模块化和异步编程" class="headerlink" title="ES6模块化和异步编程"></a>ES6模块化和异步编程</h3><p>任务</p>
<ul>
<li>如何使用ES6的模块化语法</li>
<li>如何使用Promise解决回调地狱的问题</li>
<li>如何使用async/await简化Promis的调用</li>
<li>说出宏任务和微任务的执行顺序</li>
</ul>
<h4 id="ES6模块化"><a href="#ES6模块化" class="headerlink" title="ES6模块化"></a>ES6模块化</h4><p>node.js如何实现模块化</p>
<p>node.js遵循了CommonJS的模块化规范，其中：</p>
<ul>
<li>导入其他模块可以使用require()方法</li>
<li>模块对外共享成员使用module.exports对象</li>
</ul>
<p>模块化的好处：</p>
<p>大家都遵守同样的模块化规范写代码，降低了沟通的成本，极大方便了各个模块之间的相互调用</p>
<p><strong>前端模块化的规范分类</strong></p>
<p>在ES6模块化规范诞生之前，javascript社区已经尝试出并提出了AMD，CMD，CommonJS等模块化规范</p>
<p>存在一定的差异和局限性</p>
<ul>
<li>AMD和CMD适用于浏览器端的JavaScript模块化</li>
<li>CommonJS适用于服务器端的Javascript模块化</li>
</ul>
<p>因此官方推出了统一的ES6规范</p>
<p>是统一的浏览器端和服务器端的模块化开发规范</p>
<p><strong>ES6模块化规范中定义</strong></p>
<ul>
<li>每个js文件都是一个独立的模块</li>
<li>导入其他模块成员使用import关键字</li>
<li>往外共享模块成员使用exprot关键字</li>
</ul>
<p><strong>如何在node.js中体验ES6模块化</strong></p>
<p>node.js中默认仅支持CommonJS模块化规范，想在node.js中体验ES6语法</p>
<ol>
<li>安装了v14.15,1或以上的坂本的node.js</li>
<li>在package.json的根节点添加”type”:”module”节点</li>
</ol>
<p>用vscode打开一个空文件夹</p>
<p>npm init -y快速配置一个package.json文件</p>
<p>添加</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;type&quot;</span>: <span class="string">&quot;module&quot;</span>,</span><br></pre></td></tr></table></figure>

<h5 id="模块化基本语法"><a href="#模块化基本语法" class="headerlink" title="模块化基本语法"></a>模块化基本语法</h5><ol>
<li>默认导出与默认导入</li>
<li>按需导出与按需导入</li>
<li>直接导入并执行模块中的代码</li>
</ol>
<p><strong>默认导出</strong></p>
<p>export default默认导出的成员</p>
<p>新建 n1.js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> n1 = <span class="number">10</span> <span class="comment">// 定义模块的私有成员 n1</span></span><br><span class="line"><span class="keyword">let</span> n2 = <span class="number">20</span> <span class="comment">// 定义模块私有化成员 n2(外界访问不到n2，因为没有被共享出来)</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">show</span>(<span class="params"></span>) </span>&#123; &#125; <span class="comment">// 定义模块私有化方法 show</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123; <span class="comment">// 导出n1和show</span></span><br><span class="line">    n1,</span><br><span class="line">    show</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>只允许使用一次导出</p>
<p><strong>默认导入</strong></p>
<p>默认导入的语法：import接收名称 from ‘模块标识符’</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> n1 <span class="keyword">from</span> <span class="string">&#x27;./n1.js&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(n1)</span><br></pre></td></tr></table></figure>

<p>会输出</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123; n1: 10, show: [Function: show] &#125;</span><br></pre></td></tr></table></figure>

<p>默认导入时接收名称可以任意名称，只要是合法的成员名称即可</p>
<p><strong>按需导出</strong></p>
<p>按需导出的语法：export按需导出的成员</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 当前模块 03_m2.js</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 向外按需导出变量 s1</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> s1 = <span class="string">&#x27;aaa&#x27;</span></span><br><span class="line"><span class="comment">// 向外按需导出变量 s2</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> s2 = <span class="string">&#x27;ccc&#x27;</span></span><br><span class="line"><span class="comment">// 向外按需导出方法 say</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">say</span>(<span class="params"></span>)</span></span><br></pre></td></tr></table></figure>

<p><strong>按需导入</strong></p>
<p>按需导入的语法：import { s1 } from ‘模块标识符’</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; s1,s2,say &#125; <span class="keyword">from</span> <span class="string">&#x27;./03_m2.js&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(s1)</span><br><span class="line"><span class="built_in">console</span>.log(s2)</span><br><span class="line"><span class="built_in">console</span>.log(say)</span><br></pre></td></tr></table></figure>

<p><strong>直接导入并执行模块中的代码</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 当前文件模块为 05_m3.js</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 当前模块中执行一个 for 循环</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(i)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ---------------分割线-----------------</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">&#x27;./05_m3.js&#x27;</span></span><br></pre></td></tr></table></figure>



<h4 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h4><h5 id="回调地狱"><a href="#回调地狱" class="headerlink" title="回调地狱"></a>回调地狱</h5><p>多层回调函数的相互嵌套，就形成了回调地狱，示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;	<span class="comment">// 第 1 层回调函数</span></span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;延时 1 秒后输出&#x27;</span>)</span><br><span class="line">    </span><br><span class="line">  	<span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;  <span class="comment">// 第 2 层回调函数</span></span><br><span class="line">  	  <span class="built_in">console</span>.log(<span class="string">&#x27;在延时 2 秒后输出&#x27;</span>)</span><br><span class="line">        </span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">&#x27;在延时 3 秒后输出&#x27;</span>)</span><br><span class="line">        &#125;, <span class="number">3000</span>)</span><br><span class="line">  	&#125;, <span class="number">2000</span>)</span><br><span class="line">&#125;, <span class="number">1000</span>)</span><br></pre></td></tr></table></figure>

<p>回调地狱缺点：</p>
<p>代码耦合性太强，牵一发动全身，难以维护</p>
<p>大量冗余的代码互相嵌套，可读性变差了</p>
<h5 id="如何解决"><a href="#如何解决" class="headerlink" title="如何解决"></a>如何解决</h5><p>为了解决回调地狱的问题，ES6中新增了Promise的概念</p>
<h5 id="Promise基本概念"><a href="#Promise基本概念" class="headerlink" title="Promise基本概念"></a>Promise基本概念</h5><p><strong>1.Promise是一个构造函数</strong></p>
<ul>
<li>我们可以创建Promise示例 const p = new Promise()</li>
<li>new出来的Promise示例对象，代表一个<strong>异步操作</strong></li>
</ul>
<p><strong>2.Promise.prototype上包含一个.then()方法</strong></p>
<ul>
<li>每一次new Promise()构造函数得到的实例对象</li>
<li>都可以通过原型链的方式访问到.then()方法，例如p.then()</li>
</ul>
<p><strong>3..then方法用来预先指定成功和失败的回调函数</strong></p>
<p>异步操作肯定会成功或者失败，调用.then来指定</p>
<ul>
<li>p.then（成功的回调函数，失败的回调函数）</li>
<li>p.then(result =&gt; { }, error =&gt; { })</li>
<li>调用.then()方法，成功的回调函数是必选的，失败的回调函数是可选的</li>
</ul>
<h5 id="基于回调函数按顺序读取文件内容"><a href="#基于回调函数按顺序读取文件内容" class="headerlink" title="基于回调函数按顺序读取文件内容"></a>基于回调函数按顺序读取文件内容</h5><p>三个txt文件分别内容：  111     222     333</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7HXPK0"><img src="https://s4.ax1x.com/2022/01/25/7HXPK0.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/25/7HXPK0.png" srcset="" alt="7HXPK0.png"  /></a></p>
<p>这样写就是回调地狱了</p>
<h5 id="基于then-fs来读取文件内容"><a href="#基于then-fs来读取文件内容" class="headerlink" title="基于then-fs来读取文件内容"></a>基于then-fs来读取文件内容</h5><p>需要安装then-fs第三方包</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install then-fs</span><br></pre></td></tr></table></figure>

<p>读取文件</p>
<p>调用then-fs提供的readFile()方法，可以异步读取文件的内容，他的<strong>返回值是Promise的实例对象</strong>。因此可以调用.then()方法为每个Promise异步操作指定成功和失败之后的回调函数。实例代码如下：</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7HXgRs"><img src="https://s4.ax1x.com/2022/01/25/7HXgRs.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/25/7HXgRs.png" srcset="" alt="7HXgRs.png"></a></p>
<p>上述代码无法保证顺序，可能运行 node xxx.js  输出来是  111  333  222，需要进行改造</p>
<p>改造之前，需要先了解一下.then方法的特性</p>
<h5 id="then-方法的特性"><a href="#then-方法的特性" class="headerlink" title=".then()方法的特性"></a>.then()方法的特性</h5><p>如果上一个.then方法中。返回了一个<strong>新的Promise实例对象</strong>，则可以通过下一个.then()继续进行处理。通过.then方法的链式调用，就解决了回调地狱的问题</p>
<p>Promise支持链式调用，从而解决回调地狱的问题。实例代码如下：</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7HvbK1"><img src="https://s4.ax1x.com/2022/01/25/7HvbK1.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/25/7HvbK1.png" srcset="" alt="7HvbK1.png"></a></p>
<h5 id="通过-catch捕获错误"><a href="#通过-catch捕获错误" class="headerlink" title="通过.catch捕获错误"></a>通过.catch捕获错误</h5><p>在Promise的链式操作中如果发生了错误，可以使用Promise.prototype.catch方法进行捕获和处理；</p>
<p>如果还是上面的代码但是把txt文件删除，再运行node，输出没有东西</p>
<p>最后一行加上</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.catch((err) =&gt; &#123;</span><br><span class="line">  console.log(err.message)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>如果不希望前面的错误导致后续的.then无法正常执行，则可以将.catch调用提前，实例代码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">thenFs</span><br><span class="line">	.readFile(<span class="string">&#x27;./files/11.txt&#x27;</span>, <span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line">	.catch(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">	  <span class="built_in">console</span>.log(err.message)</span><br><span class="line">	&#125;)</span><br></pre></td></tr></table></figure>

<p><code>node xxx.js</code>执行之后输出：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">undefined</span><br><span class="line">222</span><br><span class="line">333</span><br></pre></td></tr></table></figure>

<h5 id="Promise-all-方法"><a href="#Promise-all-方法" class="headerlink" title="Promise.all()方法"></a>Promise.all()方法</h5><p>Promise.all方法会发起并行的Promise异步操作，等所有的异步操作全部结束后才会执行下一步的.then操作(等待机制)。</p>
<p>示例代码如下：</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7qfS0A"><img src="https://s4.ax1x.com/2022/01/26/7qfS0A.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/26/7qfS0A.png" srcset="" alt="7qfS0A.png"></a></p>
<p>输出：111  222 333</p>
<h5 id="Promise-race-方法"><a href="#Promise-race-方法" class="headerlink" title="Promise.race()方法"></a>Promise.race()方法</h5><p>Promise.race()方法会发起并行的Promise异步操作，只要任何一个异步操作完成，就立即执行下一步.then操作。示例代码如下</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7qoj6f"><img src="https://s4.ax1x.com/2022/01/26/7qoj6f.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/26/7qoj6f.png" srcset="" alt="7qoj6f.png"></a></p>
<p>会输出：333</p>
<h5 id="基于Promise封装一个读取文件的方法"><a href="#基于Promise封装一个读取文件的方法" class="headerlink" title="基于Promise封装一个读取文件的方法"></a>基于Promise封装一个读取文件的方法</h5><p>方法的封装要求：</p>
<ol>
<li>方法的名称要定义为getFile</li>
<li>方法接收一个形参fpath，表示要读取的文件的路径</li>
<li>方法的返回值为Promise实例对象</li>
</ol>
<p>getFile方法的基本定义  </p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getFile</span>(<span class="params">fpath</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 方法的返回值为Promise的实例对象</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>代码中的new Promise()只是创建了一个<strong>形式上的异步操作</strong></p>
<h5 id="创建具体的异步操作"><a href="#创建具体的异步操作" class="headerlink" title="创建具体的异步操作"></a>创建具体的异步操作</h5><p>如果想要创建具体的异步操作，则需要在new Promise()构造函数期间，传递一个function函数，将具体的异步操作定义到function函数内部，示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getFile</span>(<span class="params">fpath</span>) </span>&#123;</span><br><span class="line">	<span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">		fs.readFile(fpath, <span class="string">&#x27;utf-8&#x27;</span>, <span class="function">(<span class="params">err, dataStr</span>) =&gt;</span> &#123;  &#125;)</span><br><span class="line">	&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h5 id="获取-then两个形参"><a href="#获取-then两个形参" class="headerlink" title="获取.then两个形参"></a>获取.then两个形参</h5><p>通过   .then()   指定的成功和失败的回调函数，可以在function的形参中进行接收，实例代码如下</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">function getFile(fpath) &#123;</span><br><span class="line">  // resolve 形参是：调用 getFiles() 方法时，通过 .then 指定的“成功的”回调函数</span><br><span class="line">  // reject 形参是： 调用 getFiles() 方法时，通过 .then 指定的“失败的”回调函数</span><br><span class="line">  return new Promise(function(resolve, reject) &#123;</span><br><span class="line">    fs.readFile(fpath, &#x27;utf8&#x27;,(err, dataStr) =&gt; &#123; &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line">// getFile 方法的调用过程</span><br><span class="line">getFile(&#x27;./files/1.txt&#x27;).then(成功的回调函数, 失败的回调函数)</span><br></pre></td></tr></table></figure>



<h5 id="调用resolve和reject回调函数"><a href="#调用resolve和reject回调函数" class="headerlink" title="调用resolve和reject回调函数"></a>调用resolve和reject回调函数</h5><p>Promise异步操作的结果，可以调用resolve或reject回调函数进行处理。示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getFile</span>(<span class="params">fpath</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// resolve 是成功的回调函数，reject 是失败的回调函数</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>&#123;</span><br><span class="line">    fs.readFile(fpath, <span class="string">&#x27;utf8&#x27;</span>, <span class="function">(<span class="params">err, dataStr</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span>(err) <span class="keyword">return</span> reject(err)	<span class="comment">// 如果读取失败，则调用“失败的回调函数”</span></span><br><span class="line">      resolve(dataStr)			   <span class="comment">// 如果读取成功，则调用“成功的回调函数”</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 调用方法，后面是参数</span></span><br><span class="line">getFile(<span class="string">&#x27;./files/1.txt&#x27;</span>).then(<span class="function">(<span class="params">r1</span>) =&gt;</span> &#123;<span class="built_in">console</span>.log(r1)&#125;, <span class="function">(<span class="params">err</span>) =&gt;</span> &#123;<span class="built_in">console</span>.log(err.message)&#125;)</span><br></pre></td></tr></table></figure>



<h4 id="async-await"><a href="#async-await" class="headerlink" title="async/await"></a>async/await</h4><p>async/await是ES8（ECMAScript 2017 ）引入的新语法，用来简化Promise异步操作。在async/await 出现之前，开发者只能通过链式 .then()</p>
<p>的方式处理Promise异步操作。示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">thenFs.readFile(<span class="string">&#x27;./files/1.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">  .then(<span class="function"><span class="params">r1</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(r1)</span><br><span class="line">    <span class="keyword">return</span> thenFs.readFile(<span class="string">&#x27;./files/2.txt&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">.then(<span class="function"><span class="params">r2</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(r2)</span><br><span class="line">    <span class="keyword">return</span> thenFs.readFile(<span class="string">&#x27;./files/3.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">.then(<span class="function"><span class="params">r3</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(r3)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>.then 链式调用的优点，解决回调地狱的问题</p>
<p>.then 链式调用的缺点，代码冗余，阅读性差，不易理解</p>
<h5 id="async-await基本使用"><a href="#async-await基本使用" class="headerlink" title="async/await基本使用"></a>async/await基本使用</h5><p>使用async/await 简化Promise异步操作的示例代码如下：</p>
<p>如果用到await，方法上必须要加上async</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> thenFs <span class="keyword">from</span> <span class="string">&#x27;then-fs&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 按照顺序读取文件 1，2，3 的内容</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getAllFile</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> r1 = <span class="keyword">await</span> thenFs.readFile(<span class="string">&#x27;./files/1.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(r1)</span><br><span class="line">    <span class="keyword">const</span> r2 = <span class="keyword">await</span> thenFs.readFile(<span class="string">&#x27;./files/2.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(r2)</span><br><span class="line">    <span class="keyword">const</span> r3 = <span class="keyword">await</span> thenFs.readFile(<span class="string">&#x27;./files/3.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(r3)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">getAllFile()</span><br></pre></td></tr></table></figure>

<h5 id="async-await的使用注意事项"><a href="#async-await的使用注意事项" class="headerlink" title="async/await的使用注意事项"></a>async/await的使用注意事项</h5><p>如果  function 中使用了 await ，则 function 必须被  async  修饰</p>
<p>在 async 方法中，第一个 await 之前的代码会同步执行，await 之后的代码会异步执行</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;A&#x27;</span>)</span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getAllFile</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;B&#x27;</span>)</span><br><span class="line">  <span class="keyword">const</span> r1 = <span class="keyword">await</span> thenFile(<span class="string">&#x27;./files/1.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">  <span class="keyword">const</span> r2 = <span class="keyword">await</span> thenFile(<span class="string">&#x27;./files/2.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">  <span class="keyword">const</span> r3 = <span class="keyword">await</span> thenFile(<span class="string">&#x27;./files/3.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">  <span class="built_in">console</span>.log(r1, r2, r3)</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;D&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">getAllFile()</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;C&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>输出顺序</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 最终输出的顺序</span><br><span class="line">A</span><br><span class="line">B</span><br><span class="line">C</span><br><span class="line">111 222 333</span><br><span class="line">D</span><br></pre></td></tr></table></figure>



<h4 id="EventLoop"><a href="#EventLoop" class="headerlink" title="EventLoop"></a>EventLoop</h4><p>JavaScripts是一门单线程的语言，也就是说，同一事件只能做一件事情。</p>
<h5 id="同步任务和异步任务"><a href="#同步任务和异步任务" class="headerlink" title="同步任务和异步任务"></a>同步任务和异步任务</h5><p>为了防止某个耗时任务导致程序假死的问题，JavaScript把待执行的任务分成了两类：</p>
<p><strong>1.同步任务（synchronous）</strong></p>
<ul>
<li>又叫做非耗时任务，指的是在主线程上排队执行的那些任务</li>
<li>只有前一个任务执行完毕，才能执行后一个任务</li>
</ul>
<p><strong>2.异步任务（asynchronous）</strong></p>
<ul>
<li>又叫做<strong>耗时任务</strong>，异步任务由Javascript<strong>委托</strong>給宿主环境进行执行</li>
<li>当异步任务执行完成后，<strong>会通知Javascript主线程</strong>执行异步任务的<strong>回调函数</strong></li>
</ul>
<h5 id="3-同步任务和异步任务的执行过程"><a href="#3-同步任务和异步任务的执行过程" class="headerlink" title="3.同步任务和异步任务的执行过程"></a>3.同步任务和异步任务的执行过程</h5><p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7O9C28"><img src="https://s4.ax1x.com/2022/01/26/7O9C28.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/26/7O9C28.png" srcset="" alt="7O9C28.png"></a></p>
<h5 id="4-EventLoop的基本概念"><a href="#4-EventLoop的基本概念" class="headerlink" title="4.EventLoop的基本概念"></a>4.EventLoop的基本概念</h5><p>结合EventLoop分析输出的顺序</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> thenFs <span class="keyword">from</span> <span class="string">&#x27;then-fs&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;A&#x27;</span>)</span><br><span class="line">thenFs.readFile(<span class="string">&#x27;./files/1.txt&#x27;</span>, <span class="string">&#x27;utf8&#x27;</span>).then(<span class="function"><span class="params">dataStr</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;B&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;C&#x27;</span>)</span><br><span class="line">&#125;,<span class="number">0</span>)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;D&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>最后输出的结果其实是：ADCB</p>
<p>A和D属于同步任务。会根据代码的先后顺序依次执行</p>
<ol>
<li>首先执行A</li>
<li>然后会执行读取操作，但是会发现是一个异步的耗时任务，于是js把这个操作委托给了环境去执行</li>
<li>然后下面是一个延时器，也是一个耗时任务，也委托了</li>
<li>同步任务，然后执行输出D</li>
<li>先输出C是因为延时器被延迟了0毫秒</li>
<li>输出B</li>
</ol>
<h4 id="宏任务和微任务"><a href="#宏任务和微任务" class="headerlink" title="宏任务和微任务"></a>宏任务和微任务</h4><h5 id="什么是宏任务和微任务"><a href="#什么是宏任务和微任务" class="headerlink" title="什么是宏任务和微任务"></a><strong>什么是宏任务和微任务</strong></h5><p>JavaScript把异步任务又做了进一步的划分，异步任务又分为两类，分别是</p>
<p><strong>1.宏任务（macrotask）</strong></p>
<ul>
<li>异步的Ajax请求</li>
<li>setTimeout，setInterval（延时器，定时器）</li>
<li>文件操作</li>
<li>其他宏任务</li>
</ul>
<p><strong>2.微任务（microtask）</strong></p>
<ul>
<li>Promise.then，.catch，.finally</li>
<li>process.nextTick</li>
<li>其他微任务</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7OgfOJ"><img src="https://s4.ax1x.com/2022/01/27/7OgfOJ.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/27/7OgfOJ.png" srcset="" alt="7OgfOJ.png" style="zoom:80%;" /></a></p>
<h5 id="宏任务和微任务的执行顺序"><a href="#宏任务和微任务的执行顺序" class="headerlink" title="宏任务和微任务的执行顺序"></a><strong>宏任务和微任务的执行顺序</strong></h5><p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7Xu5z4"><img src="https://s4.ax1x.com/2022/01/27/7Xu5z4.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/27/7Xu5z4.png" srcset="" alt="7Xu5z4.png" style="zoom:80%;" /></a></p>
<p>例子：</p>
<p> <a target="_blank" rel="noopener" href="https://imgtu.com/i/7jCTnU"><img src="https://s4.ax1x.com/2022/01/27/7jCTnU.md.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/27/7jCTnU.md.png" srcset="" alt="7jCTnU.md.png"></a></p>
<p>分析以下的代码的输出顺序：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">setTimeout</span>(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;1&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;2&#x27;</span>)</span><br><span class="line">  resolve()</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;3&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">&#x27;4&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>第一个是定时器，（宏任务）</p>
<p>下面new一个Promise，会同步执行function （同步任务）</p>
<p>.then 很显然是一个微任务啊</p>
<p>console.log 是一个同步的任务</p>
<p>正确顺序是：2431</p>
<p>分析：</p>
<p>1.先执行所有的同步任务</p>
<ul>
<li>执行第6行，第12行代码</li>
</ul>
<p>2.再执行微任务</p>
<ul>
<li>执行第9行代码</li>
</ul>
<p>3.在执行下一个宏任务</p>
<ul>
<li>执行第2行代码</li>
</ul>
<p>分析以下的执行顺序（代码较长，截取成了左中右3个部分）</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/7jnDeI"><img src="https://s4.ax1x.com/2022/01/27/7jnDeI.md.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/27/7jnDeI.md.png" srcset="" alt="7jnDeI.md.png"></a></p>
<p>顺序：156234789</p>
<h4 id="API接口案例"><a href="#API接口案例" class="headerlink" title="API接口案例"></a>API接口案例</h4><p>基于MySQL数据库 + Express 对外提供用户列表的API接口服务。用到的技术如下：</p>
<ul>
<li>第三方包 express 和 mysql2</li>
<li>ES6 模块化</li>
<li>Promise</li>
<li>async/await</li>
</ul>
<h5 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h5><ol>
<li>搭建项目的基本结构</li>
<li>创建基本的服务器</li>
<li>创建db数据库操作模块</li>
<li>创建 user_ctrl 业务模块</li>
<li>创建 user_router 路由模块</li>
</ol>
<h5 id="搭建项目的基本结构"><a href="#搭建项目的基本结构" class="headerlink" title="搭建项目的基本结构"></a>搭建项目的基本结构</h5><p>1.启用ES6模块化支持</p>
<ul>
<li>在package.json中声明 “type”:”module”</li>
</ul>
<p>2.安装第三方依赖包</p>
<ul>
<li>运行   npm install <a href="mailto:&#101;&#120;&#112;&#x72;&#101;&#115;&#x73;&#x40;&#52;&#46;&#x31;&#x37;&#46;&#49;">&#101;&#120;&#112;&#x72;&#101;&#115;&#x73;&#x40;&#52;&#46;&#x31;&#x37;&#46;&#49;</a> <a href="mailto:&#109;&#x79;&#115;&#113;&#108;&#50;&#x40;&#x32;&#x2e;&#50;&#x2e;&#x35;">&#109;&#x79;&#115;&#113;&#108;&#50;&#x40;&#x32;&#x2e;&#50;&#x2e;&#x35;</a></li>
</ul>
<p>创建文件夹code1，终端运行 npm init -y初始化项目</p>
<p>package.json</p>
<p>安装后：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">&quot;type&quot;</span>: <span class="string">&quot;module&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;code1&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;version&quot;</span>: <span class="string">&quot;1.0.0&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;description&quot;</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;main&quot;</span>: <span class="string">&quot;index.js&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;scripts&quot;</span>: &#123;</span><br><span class="line">    <span class="attr">&quot;test&quot;</span>: <span class="string">&quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">&quot;keywords&quot;</span>: [],</span><br><span class="line">  <span class="attr">&quot;author&quot;</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;license&quot;</span>: <span class="string">&quot;ISC&quot;</span>,</span><br><span class="line">  <span class="attr">&quot;dependencies&quot;</span>: &#123;</span><br><span class="line">    <span class="attr">&quot;express&quot;</span>: <span class="string">&quot;^4.17.1&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;mysql2&quot;</span>: <span class="string">&quot;^2.2.5&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>创建基本的服务器</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用 ES6 的默认导入语法</span></span><br><span class="line"><span class="keyword">import</span> express <span class="keyword">from</span> <span class="string">&#x27;express&#x27;</span></span><br><span class="line"><span class="keyword">const</span> app = express()</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">80</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>通过   nodemon app.js   来运行</p>
<p><strong>创建db数据库操作模块</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> mysql <span class="keyword">from</span> <span class="string">&#x27;mysql2&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> pool = mysql.createPool(&#123;</span><br><span class="line">  <span class="attr">host</span>: <span class="string">&#x27;127.0.0.1&#x27;</span>,</span><br><span class="line">  <span class="attr">port</span>: <span class="number">3306</span>,</span><br><span class="line">  <span class="attr">database</span>: <span class="string">&#x27;my_db_01&#x27;</span>,   <span class="comment">// 请填写要操作的数据库名称</span></span><br><span class="line">  <span class="attr">user</span>: <span class="string">&#x27;root&#x27;</span>,           <span class="comment">// 请填写登录数据库的用户名</span></span><br><span class="line">  <span class="attr">password</span>: <span class="string">&#x27;admin123&#x27;</span>,   <span class="comment">// 请填写登录数据库的密码</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 默认导出一个支持 Promise API 的 pool</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> pool.promise()</span><br></pre></td></tr></table></figure>

<p><strong>创建 user_ctrl 模块</strong></p>
<p>创建 controller 文件夹，内部创建  user_ctrl.js 文件</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> db <span class="keyword">from</span> <span class="string">&#x27;../db/index&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取所有用户的列表数据</span></span><br><span class="line"><span class="comment">// 使用ES6的按需导出语法</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getAllUser</span>(<span class="params">req,res</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// db.query() 函数的返回值是 Promise 的实例对象，因此，可以使用 async/await 进行简化</span></span><br><span class="line">  <span class="keyword">const</span> [rows] = <span class="keyword">await</span> db.query(<span class="string">&#x27;select id, username, nickname from ev_users&#x27;</span>)</span><br><span class="line">  res.send(&#123;</span><br><span class="line">    <span class="attr">status</span>: <span class="number">0</span>,</span><br><span class="line">    <span class="attr">message</span>: <span class="string">&#x27;获取用户数据成功&#x27;</span>,</span><br><span class="line">    <span class="attr">data</span>: rows</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>创建并使用 user_route 模块</strong></p>
<p>新建  router  文件夹，新建   user_router.js   模块</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> express <span class="keyword">from</span> <span class="string">&#x27;express&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; getAllUser &#125; <span class="keyword">from</span> <span class="string">&#x27;../controller/user_ctrl&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> express.Router()</span><br><span class="line"><span class="comment">// 挂载路由规则</span></span><br><span class="line"><span class="comment">// 只要用户是get请求请求/user这个地址,就交给getAllUser来处理</span></span><br><span class="line">router.get(<span class="string">&#x27;/user&#x27;</span>, getAllUser)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> router</span><br></pre></td></tr></table></figure>

<p><strong>导入并挂载路由模块</strong></p>
<p>在app.js入口中导入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用 ES6 的默认导入语法</span></span><br><span class="line"><span class="keyword">import</span> express <span class="keyword">from</span> <span class="string">&#x27;express&#x27;</span></span><br><span class="line"><span class="keyword">import</span> userRouter <span class="keyword">from</span> <span class="string">&#x27;./router/user_router&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = express()</span><br><span class="line"></span><br><span class="line">app.use(<span class="string">&#x27;/api&#x27;</span>, userRouter)</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">80</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>nodemon app.js来运行项目</p>
<p>没有nodemon就全局安装一个</p>
<p>这里链接的是mysql，我说怎么连不上我日</p>
<h5 id="使用try-catch捕获异常"><a href="#使用try-catch捕获异常" class="headerlink" title="使用try_catch捕获异常"></a>使用try_catch捕获异常</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getAllUser</span>(<span class="params">req,res</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 使用try_catch来捕获 Promise 异步任务中产生的异常错误，并在 catch块 中处理</span></span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> [rows] = <span class="keyword">await</span> db.query(<span class="string">&#x27;select id, username, nickname from ev_users&#x27;</span>)</span><br><span class="line">    res.send(&#123;</span><br><span class="line">      <span class="attr">status</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">message</span>: <span class="string">&#x27;获取用户数据成功&#x27;</span>,</span><br><span class="line">      <span class="attr">data</span>: rows</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">     res.send(&#123; <span class="attr">status</span>: <span class="number">1</span>,<span class="attr">message</span>: <span class="string">&#x27;获取用户列表数据失败&#x27;</span>, <span class="attr">desc</span>: e.message &#125;)   </span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="vue3"><a href="#vue3" class="headerlink" title="vue3"></a>vue3</h3><h4 id="vue3的新特性"><a href="#vue3的新特性" class="headerlink" title="vue3的新特性"></a>vue3的新特性</h4><p>1.vue3采用渐进式开发，向下兼容</p>
<p>2.性能的提升</p>
<ul>
<li>打包大小减少了41%</li>
<li>初次渲染快了55%</li>
<li>更新快了133%</li>
<li>内存使用减少了54%</li>
</ul>
<p>3.Composition API 的集合，解决Vue2组件开发问题</p>
<p>4.新的 API 加入</p>
<ul>
<li>Teleport瞬移组件</li>
<li>Suspense 解决异步加载组件问题</li>
</ul>
<p>5.更好的 TypeScript 支持</p>
<ul>
<li>vue2集成typeScript支持</li>
</ul>
<h4 id="Vue-cli构建项目"><a href="#Vue-cli构建项目" class="headerlink" title="Vue-cli构建项目"></a>Vue-cli构建项目</h4><p>新建文件夹，vscode打开</p>
<p>终端执行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm create vue3-1</span><br></pre></td></tr></table></figure>

<ul>
<li>第一步：选择手动配置</li>
<li>第二步：除了默认的选项，先直接选上typeScript，其他先不选</li>
<li>第三步：Use class-style component syntax? No</li>
<li>第四步：Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No</li>
<li>第五步：Pick a linter / formatter config ，这里选择第一项就可以了</li>
<li>第六步：Pick additional lint features，选择Lint on save</li>
<li>第七步：Where do you prefer placing config for Babel, ESLint, etc.? ，选择In dedicated config files </li>
</ul>
<p>或许也可以使用命令<code>vue ui</code>命令来开启UI构建项目</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/HSJJET"><img src="https://s4.ax1x.com/2022/01/29/HSJJET.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/29/HSJJET.png" srcset="" alt="HSJJET.png" style="zoom:80%;" /></a></p>
<p>使用npm包管理，如果安装了yarn可以用yarn会快点</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/HSJyVK"><img src="https://s4.ax1x.com/2022/01/29/HSJyVK.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/29/HSJyVK.png" srcset="" alt="HSJyVK.png" style="zoom:80%;" /></a></p>
<p>后面选择和命令安装是一样的</p>
<p>选完后，看见终端已经在构建了</p>
<p>构建完后就是</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/HSUqwq"><img src="https://s4.ax1x.com/2022/01/29/HSUqwq.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/29/HSUqwq.png" srcset="" alt="HSUqwq.png" style="zoom: 50%;" /></a></p>
<p>项目结构:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">|-node_modules       -- 所有的项目依赖包都放在这个目录下</span><br><span class="line">|-public             -- 公共文件夹</span><br><span class="line">---|favicon.ico      -- 网站的显示图标</span><br><span class="line">---|index.html       -- 入口的html文件</span><br><span class="line">|-src                -- 源文件目录，编写的代码基本都在这个目录下</span><br><span class="line">---|assets           -- 放置静态文件的目录，比如logo.pn就放在这里</span><br><span class="line">---|components       -- Vue的组件文件，自定义的组件都会放到这</span><br><span class="line">---|App.vue          -- 根组件，这个在Vue2中也有</span><br><span class="line">---|main.ts          -- 入口文件，因为采用了TypeScript所以是ts结尾</span><br><span class="line">---|shims-vue.d.ts   -- 类文件(也叫定义文件)，因为.vue结尾的文件在ts中不认可，所以要有定义文件</span><br><span class="line">|-.browserslistrc    -- 在不同前端工具之间公用目标浏览器和node版本的配置文件，作用是设置兼容性</span><br><span class="line">|-.eslintrc.js       -- Eslint的配置文件，不用作过多介绍</span><br><span class="line">|-.gitignore         -- 用来配置那些文件不归git管理</span><br><span class="line">|-package.json       -- 命令配置和包管理文件</span><br><span class="line">|-README.md          -- 项目的说明文件，使用markdown语法进行编写</span><br><span class="line">|-tsconfig.json      -- 关于TypoScript的配置文件</span><br><span class="line">|-yarn.lock          -- 使用yarn后自动生成的文件，由Yarn管理，安装yarn包时的重要信息存储到yarn.lock文件中</span><br></pre></td></tr></table></figure>

<h4 id="Vue3生命周期的不一样"><a href="#Vue3生命周期的不一样" class="headerlink" title="Vue3生命周期的不一样"></a>Vue3生命周期的不一样</h4><p><img src="https://img.kancloud.cn/c1/fb/c1fba077d7ca9044912b2bf602dd1cb4_303x510.png" class="lazyload" data-srcset="https://img.kancloud.cn/c1/fb/c1fba077d7ca9044912b2bf602dd1cb4_303x510.png" srcset=""></p>
<p>发现了别人写的笔记，还不错：<a target="_blank" rel="noopener" href="https://www.kancloud.cn/xiaomingjun/vue_js/1655333">vue 3.0 · VUE · 看云 (kancloud.cn)</a></p>
<p>差不多就不写了</p>
<p>由于我们使用了TypeScript，所以有些文件是以ts结尾的</p>
<p>shim-vue.d.ts是声明的文件，让ts支持vue</p>
<p>可以看看main.ts入口</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; createApp &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> App <span class="keyword">from</span> <span class="string">&#x27;./App.vue&#x27;</span></span><br><span class="line"></span><br><span class="line">createApp(App).mount(<span class="string">&#x27;#app&#x27;</span>)</span><br></pre></td></tr></table></figure>



<h4 id="Vue3中的setup-和ref-函数制作点餐例子"><a href="#Vue3中的setup-和ref-函数制作点餐例子" class="headerlink" title="Vue3中的setup()和ref()函数制作点餐例子"></a>Vue3中的setup()和ref()函数制作点餐例子</h4><p><strong>在setup函数中，可以使用ref函数，用于创建一个响应式数据，当数据发生改变时，Vue会自动更新UI</strong></p>
<p>setup()函数：<a target="_blank" rel="noopener" href="https://v3.cn.vuejs.org/guide/composition-api-setup.html#%E8%AE%BF%E9%97%AE%E7%BB%84%E4%BB%B6%E7%9A%84-property">https://v3.cn.vuejs.org/guide/composition-api-setup.html#%E8%AE%BF%E9%97%AE%E7%BB%84%E4%BB%B6%E7%9A%84-property</a></p>
<p>要使用ref函数，就在import按需引入ref</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; defineComponent, ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> defineComponent(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;App&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>原来vue2的写法</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> defineComponent(&#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;App&#x27;</span>,</span><br><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  </span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">method</span>: &#123;</span><br><span class="line">  </span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>现在可以直接使用setup()</p>
<p><strong>Vue3的语法</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;img alt=&quot;Vue logo&quot; src=&quot;./assets/logo.png&quot;&gt;</span><br><span class="line">  &lt;h2&gt;欢迎光临点餐中心&lt;/h2&gt;</span><br><span class="line">  &lt;div&gt;请选择一位侍者为你服务&lt;/div&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;button v-for=&quot;(item,index) in mans&quot; :key=&quot;index&quot;&gt;</span><br><span class="line">      双大括号 index 双大括号:双大括号 item 双大括号</span><br><span class="line">    &lt;/button&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; defineComponent, ref &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">export default defineComponent(&#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    const mans = ref([&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;])</span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      mans</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>以下都使用了Vue3的语法</p>
<h5 id="完整写完点餐例子，使用新的Vue3语法"><a href="#完整写完点餐例子，使用新的Vue3语法" class="headerlink" title="完整写完点餐例子，使用新的Vue3语法"></a>完整写完点餐例子，使用新的Vue3语法</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;img alt=&quot;Vue logo&quot; src=&quot;./assets/logo.png&quot;&gt;</span><br><span class="line">  &lt;h2&gt;欢迎光临点餐中心&lt;/h2&gt;</span><br><span class="line">  &lt;div&gt;请选择一位侍者为你服务&lt;/div&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;button v-for=&quot;(item,index) in mans&quot; :key=&quot;index&quot; @click=&quot;selectManFun(index)&quot;&gt;</span><br><span class="line">      双大括号 index 双大括号:双大括号 item 双大括号</span><br><span class="line">    &lt;/button&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    你选择了:双大括号 selectMan 双大括号 为你服务</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; defineComponent, ref &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">export default defineComponent(&#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    // 服务员列表</span><br><span class="line">    const mans = ref([&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;])</span><br><span class="line">    // 用户选择了谁</span><br><span class="line">    const selectMan = ref(&#x27;&#x27;)</span><br><span class="line">    // 定义方法来选择服务员,箭头函数形式,接收一个索引值，因为使用的是typescript所以后面要加上:number</span><br><span class="line">    const selectManFun = (index: number) =&gt; &#123;</span><br><span class="line">      // 原来的赋值方法：selectMan = mans[index] 这样是不行的，在这里只能</span><br><span class="line">      selectMan.value = mans.value[index]</span><br><span class="line">    &#125;</span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      mans,</span><br><span class="line">      selectMan,</span><br><span class="line">      // 方法写完了也得暴露出去</span><br><span class="line">      selectManFun</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h5 id="总结：Vue3代码特点"><a href="#总结：Vue3代码特点" class="headerlink" title="总结：Vue3代码特点"></a>总结：Vue3代码特点</h5><ol>
<li>Vue3的新语法Setup()，不用写data，method了</li>
<li>Vue3的ref函数用于创建一个响应式数据，赋值数据要加上一个value</li>
<li>在模板中使用的数据都要 return 出去</li>
</ol>
<h5 id="使用reactive-函数优化代码"><a href="#使用reactive-函数优化代码" class="headerlink" title="使用reactive()函数优化代码"></a>使用reactive()函数优化代码</h5><p><code>reactive</code>的用法与<code>ref</code>的用法相似，也是将数据变成响应式数据，当数据发生变化时<code>UI</code>也会自动更新。不同的是<code>ref</code>用于基本数据类型，而<code>reactive</code>是用于复杂数据类型，比如对象和数组</p>
<p>先修改一下 export default 形式</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; defineComponent, ref, reactive &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    // 服务员列表</span><br><span class="line">    const mans = ref([&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;])</span><br><span class="line">    // 用户选择了谁</span><br><span class="line">    const selectMan = ref(&#x27;&#x27;)</span><br><span class="line">    // 定义方法来选择服务员,箭头函数形式,接收一个索引值，因为使用的是typescript所以后面要加上:number</span><br><span class="line">    const selectManFun = (index: number) =&gt; &#123;</span><br><span class="line">      // 原来的赋值方法：selectMan = mans[index] 这样是不行的，在这里只能</span><br><span class="line">      selectMan.value = mans.value[index]</span><br><span class="line">    &#125;</span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      mans,</span><br><span class="line">      selectMan,</span><br><span class="line">      // 方法写完了也得暴露出去</span><br><span class="line">      selectManFun</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>使用 reactive 函数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;img alt=&quot;Vue logo&quot; src=&quot;./assets/logo.png&quot;&gt;</span><br><span class="line">  &lt;h2&gt;欢迎光临点餐中心&lt;/h2&gt;</span><br><span class="line">  &lt;div&gt;请选择一位侍者为你服务&lt;/div&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;button v-for=&quot;(item,index) in data.mans&quot; :key=&quot;index&quot; @click=&quot;data.selectManFun(index)&quot;&gt;</span><br><span class="line">      双大括号 index 双大括号:双大括号 item 双大括号</span><br><span class="line">    &lt;/button&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    你选择了:双大括号 data.selectMan 双大括号 为你服务</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; defineComponent, ref, reactive &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    const data = reactive(&#123;</span><br><span class="line">      mans: [&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;],</span><br><span class="line">      selectMan: &#x27;&#x27;,</span><br><span class="line">      selectManFun: (index: number) =&gt; &#123;</span><br><span class="line">        data.selectMan = data.mans[index]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      // 写完了也得暴露出去</span><br><span class="line">      data</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>这时的代码虽然可以完美的运行，但是细心的小伙伴可以发现<code>data</code>这个变量，我们并没有作<code>类型注解</code>，而是采用了<code>TypeScript</code>的类型推断。</p>
<p>在公司的代码规范不允许出现的，这也是typeScript的要求的</p>
<p>用接口的形式来写，</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; defineComponent, ref, reactive &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">interface DataProps &#123;</span><br><span class="line">  mans: string[]</span><br><span class="line">  selectMan: string</span><br><span class="line">  selectManFun: (index: number) =&gt; void</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    const data: DataProps = reactive(&#123;</span><br><span class="line">      mans: [&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;],</span><br><span class="line">      selectMan: &#x27;&#x27;,</span><br><span class="line">      selectManFun: (index: number) =&gt; &#123;</span><br><span class="line">        data.selectMan = data.mans[index]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      // 写完了也得暴露出去</span><br><span class="line">      data</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>模板里面有很多data，要是用扩展运算符来像省略掉的话：<code>...data</code>，是不行的</p>
<p>那么有没有方法在模板中省略掉 data. 的写法呢</p>
<h5 id="vue3提供了torefs函数"><a href="#vue3提供了torefs函数" class="headerlink" title="vue3提供了torefs函数"></a>vue3提供了torefs函数</h5><p><code>toRefs()</code>将响应式的对象变为普通对象 再解构，在模板中就可以直接使用属性，不用<code>data.mans</code></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; ref, reactive, toRefs &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">interface DataProps &#123;</span><br><span class="line">  mans: string[]</span><br><span class="line">  selectMan: string</span><br><span class="line">  selectManFun: (index: number) =&gt; void</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    const data: DataProps = reactive(&#123;</span><br><span class="line">      mans: [&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;],</span><br><span class="line">      selectMan: &#x27;&#x27;,</span><br><span class="line">      selectManFun: (index: number) =&gt; &#123;</span><br><span class="line">        data.selectMan = data.mans[index]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    // 使用toRefs包装data</span><br><span class="line">    const refData = toRefs(data)</span><br><span class="line"></span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      // 写完了也得暴露出去</span><br><span class="line">      // ... 是扩展运算符</span><br><span class="line">      ...refData</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h4 id="Vue3的生命周期"><a href="#Vue3的生命周期" class="headerlink" title="Vue3的生命周期"></a>Vue3的生命周期</h4><p>组件的生命周期</p>
<h5 id="setup"><a href="#setup" class="headerlink" title="setup"></a>setup</h5><p><strong>setup()是在我们的组件创建之前，相当于运行在Vue2的beforeCreate和crea ted之前，所以在vue3中使用setup就相当于使用了这两个</strong></p>
<h5 id="onBeforeMount"><a href="#onBeforeMount" class="headerlink" title="onBeforeMount"></a>onBeforeMount</h5><p><strong>onBeforeMount是在组件挂载之前</strong></p>
<h5 id="onMounted"><a href="#onMounted" class="headerlink" title="onMounted"></a>onMounted</h5><p><strong>在组件挂载之后</strong></p>
<p>编写代码来看看执行顺序</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; ref, reactive, toRefs, onBeforeMount, onMounted &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> DataProps &#123;</span><br><span class="line">  <span class="attr">mans</span>: <span class="built_in">string</span>[]</span><br><span class="line">  <span class="attr">selectMan</span>: <span class="built_in">string</span></span><br><span class="line">  <span class="attr">selectManFun</span>: <span class="function">(<span class="params">index: <span class="built_in">number</span></span>) =&gt;</span> <span class="built_in">void</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;App&#x27;</span>,</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;1.开始创建组件 setup 函数&#x27;</span>)</span><br><span class="line">    <span class="keyword">const</span> data: DataProps = reactive(&#123;</span><br><span class="line">      <span class="attr">mans</span>: [<span class="string">&#x27;大脚&#x27;</span>, <span class="string">&#x27;张三&#x27;</span>, <span class="string">&#x27;李四&#x27;</span>],</span><br><span class="line">      <span class="attr">selectMan</span>: <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">      <span class="attr">selectManFun</span>: <span class="function">(<span class="params">index: <span class="built_in">number</span></span>) =&gt;</span> &#123;</span><br><span class="line">        data.selectMan = data.mans[index]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="comment">// 在组件挂载到节点之前</span></span><br><span class="line">    onBeforeMount(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">&#x27;2.组件挂载到页面前执行 onBeforeMount 函数 &#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    onMounted(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">&#x27;3.组件挂载到页面之后执行 onMounted 函数 &#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="comment">// 使用toRefs包装data</span></span><br><span class="line">    <span class="keyword">const</span> refData = toRefs(data)</span><br><span class="line">    <span class="comment">// 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="comment">// 写完了也得暴露出去</span></span><br><span class="line">      <span class="comment">// ... 是扩展运算符</span></span><br><span class="line">      ...refData</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>输出是：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span>开始创建组件 setup 函数</span><br><span class="line"><span class="number">2.</span>组件挂载到页面前执行 onBeforeMount 函数 </span><br><span class="line"><span class="number">3.</span>组件挂载到页面之后执行 onMounted 函数 </span><br></pre></td></tr></table></figure>



<h5 id="onBeforeUpdate"><a href="#onBeforeUpdate" class="headerlink" title="onBeforeUpdate"></a>onBeforeUpdate</h5><p>组件更新之前执行</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">onBeforeUpdate(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;4.组件更新之前执行 onBeforeUpdate 函数 &#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>



<h5 id="onUpdated"><a href="#onUpdated" class="headerlink" title="onUpdated"></a>onUpdated</h5><p>组件更新之后执行 onUpdated 函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">onUpdated(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;5.组件更新之后执行 onUpdated 函数 &#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>点击按钮改变页面</p>
<p>输出</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">4.</span>组件更新之前执行 onBeforeUpdate 函数 </span><br><span class="line"><span class="number">5.</span>组件更新之后执行 onUpdated 函数 </span><br></pre></td></tr></table></figure>

<p>还有一些钩子函数不好演示啊</p>
<h5 id="onBeforeUnmount"><a href="#onBeforeUnmount" class="headerlink" title="onBeforeUnmount"></a>onBeforeUnmount</h5><p>组件卸载之前执行的</p>
<h5 id="onUnmounted"><a href="#onUnmounted" class="headerlink" title="onUnmounted"></a>onUnmounted</h5><p>组件销毁之后执行</p>
<p>以下两个只有在我们使用<keep-alive></keep-alive>的时候才会多出来</p>
<h5 id="onActivated"><a href="#onActivated" class="headerlink" title="onActivated"></a>onActivated</h5><h5 id="onDeactivated"><a href="#onDeactivated" class="headerlink" title="onDeactivated"></a>onDeactivated</h5><h5 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h5><ul>
<li>setup() :开始创建组件之前，在<code>beforeCreate</code>和<code>created</code>之前执行。创建的是<code>data</code>和<code>method</code></li>
<li>onBeforeMount() : 组件挂载到节点上之前执行的函数。</li>
<li>onMounted() : 组件挂载完成后执行的函数。</li>
<li>onBeforeUpdate(): 组件更新之前执行的函数。</li>
<li>onUpdated(): 组件更新完成之后执行的函数。</li>
<li>onBeforeUnmount(): 组件卸载之前执行的函数。</li>
<li>onUnmounted(): 组件卸载完成后执行的函数</li>
<li>onActivated(): 被包含在<code>&lt;keep-alive&gt;</code>中的组件，会多出两个生命周期钩子函数。被激活时执行。</li>
<li>onDeactivated(): 比如从 A 组件，切换到 B 组件，A 组件消失时执行。</li>
<li>onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数（以后用到再讲，不好展现）。</li>
</ul>
<p>注：使用<code>&lt;keep-alive&gt;</code>组件会将数据保留在内存中，比如我们不想每次看到一个页面都重新加载数据，就可以使用<code>&lt;keep-alive&gt;</code>组件解决。</p>
<p>onErrorCaptured() 捕获异常时的钩子函数</p>
<h4 id="钩子函数"><a href="#钩子函数" class="headerlink" title="钩子函数"></a>钩子函数</h4><p>每个周期干什么的函数就叫钩子函数（就是上面的那些）</p>
<p>那<code>Vue2.X</code>版本的生命周期函数还可以使用吗?答案是肯定的。</p>
<p>你可以在<code>setup()</code>函数之后编写<code>Vue2</code>的生命周期函数，代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">beforeCreate</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;1-组件创建之前-----beforeCreate()&quot;</span>);</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="title">beforeMount</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;2-组件挂载到页面之前执行-----BeforeMount()&quot;</span>);</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="title">mounted</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;3-组件挂载到页面之后执行-----Mounted()&quot;</span>);</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="title">beforeUpdate</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;4-组件更新之前-----BeforeUpdate()&quot;</span>);</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="title">updated</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;5-组件更新之后-----Updated()&quot;</span>);</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<p>这时候可以看到，原来的生命周期也是完全可以使用。</p>
<h4 id="vue2和vue3生命周期对比"><a href="#vue2和vue3生命周期对比" class="headerlink" title="vue2和vue3生命周期对比"></a>vue2和vue3生命周期对比</h4><p>你也许会问，那我到底是使用<code>Vue2.x</code>还是<code>Vue3.x</code>的生命周期钩子函数？其实这个无所谓，但是不愿混用，如果你用 setup 这种<code>Vue3</code>的生命周期函数，就不要再使用<code>Vue2</code>的了。为了你更好的掌握，我作了一个函数对比：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Vue2--------------vue3</span><br><span class="line">beforeCreate  -&gt; setup()</span><br><span class="line">created       -&gt; setup()</span><br><span class="line">beforeMount   -&gt; onBeforeMount</span><br><span class="line">mounted       -&gt; onMounted</span><br><span class="line">beforeUpdate  -&gt; onBeforeUpdate</span><br><span class="line">updated       -&gt; onUpdated</span><br><span class="line">beforeDestroy -&gt; onBeforeUnmount</span><br><span class="line">destroyed     -&gt; onUnmounted</span><br><span class="line">activated     -&gt; onActivated</span><br><span class="line">deactivated   -&gt; onDeactivated</span><br><span class="line">errorCaptured -&gt; onErrorCaptured</span><br></pre></td></tr></table></figure>

<p>通过这样对比，可以很容易的看出 vue3 的钩子函数基本是再 vue2 的基础上加了一个<code>on</code>,但也有两个钩子函数发生了变化。</p>
<ul>
<li><code>BeforeDestroy</code>变成了<code>onBeforeUnmount</code></li>
<li><code>destroyed</code>变成了<code>onUnmounted</code></li>
</ul>
<p>尤大的介绍是<code>mount</code>比<code>Destroy</code>更形象，也和<code>beforeMount</code>相对应。</p>
<p>除了这些钩子函数外，<code>Vue3.x</code>还增加了<code>onRenderTracked</code>和<code>onRenderTriggered</code>函数，这两个函数放到下节课再讲解。这节就先到这里了。</p>
<h4 id="onRenderTracked-状态追踪"><a href="#onRenderTracked-状态追踪" class="headerlink" title="onRenderTracked 状态追踪"></a>onRenderTracked 状态追踪</h4><p>这两个钩子函数是<code>Vue3.x</code>版本新加的两个钩子函数，官方说是用来调试使用的，但是目前还没有给出具体的调试案例。</p>
<p>Vue 官方的文档里，明确指出了。如果你使用 Vue3，请尽量使用新的生命周期钩子函数，也就是上节课写在<code>setup()</code>函数中带<code>on</code>的这些钩子函数。</p>
<p><code>onRenderTracked</code>直译过来就是<code>状态跟踪</code>，它会跟踪页面上所有响应式变量和方法的状态，也就是我们用<code>return</code>返回去的值，他都会跟踪。只要页面有<code>update</code>的情况，他就会跟踪，然后生成一个<code>event</code>对象，我们通过<code>event</code>对象来查找程序的问题所在。</p>
<p>使用<code>onRenderTracked</code>同样要使用<code>import</code>进行引入。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; .... ,onRenderTracked,&#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>引用后就可以在<code>setup()</code>函数中进行引用了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">onRenderTracked(<span class="function">(<span class="params">event</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;状态跟踪组件-----------&gt;&quot;</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(event);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>写完后可以到终端中启动测试服务<code>yarn serve</code>,然后看一下效果，在组件没有更新的时候<code>onRenderTracked</code>是不会执行的，组件更新时，他会跟组里边每个值和方法的变化。</p>
<h4 id="onRenderTriggered-状态触发"><a href="#onRenderTriggered-状态触发" class="headerlink" title="onRenderTriggered 状态触发"></a>onRenderTriggered 状态触发</h4><p><code>onRenderTriggered</code>直译过来是<code>状态触发</code>，它不会跟踪每一个值，而是给你变化值的信息，并且新值和旧值都会给你明确的展示出来。</p>
<p>如果把<code>onRenderTracked</code>比喻成散弹枪，每个值都进行跟踪，那<code>onRenderTriggered</code>就是狙击枪，只精确跟踪发生变化的值，进行针对性调试。</p>
<p>使用它同样要先用<code>import</code>进行引入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; .... ,onRenderTriggered,&#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br></pre></td></tr></table></figure>

<p><strong>在使用<code>onRenderTriggered</code>前，记得注释相应的<code>onRenderTracked</code>代码</strong>，这样看起来会直观很多。 然后把<code>onRenderTriggered()</code>函数，写在<code>setup()</code>函数里边，</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">onRenderTriggered(<span class="function">(<span class="params">event</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&quot;状态触发组件---------------&gt;&quot;</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(event);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>对 event 对象属性的详细介绍：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">- key 那边变量发生了变化</span><br><span class="line">- newValue 更新后变量的值</span><br><span class="line">- oldValue 更新前变量的值</span><br><span class="line">- target 目前页面中的响应变量和函数</span><br></pre></td></tr></table></figure>

<p>通过这些你能很好的对代码进行调试。这些调试用的钩子函数，如果你能正确合理的使用，是真的可以快速解决问题的。</p>
<p>有的小伙伴看到这里肯定会觉的，这个和<code>watch</code>很像，那下节课我们再讲一下<code>watch</code>的使用吧，这个也有了很大的变化。</p>
<h4 id="Vue3中watch的使用和注意事项"><a href="#Vue3中watch的使用和注意事项" class="headerlink" title="Vue3中watch的使用和注意事项"></a>Vue3中watch的使用和注意事项</h4><p>当你点击按钮，点餐完毕，WEB标题也要跟着改变，这时候你好像没办法变成自动相应，双向绑定了。今天的主角就排上用场了,<code>watch</code>监听器隆重登场。</p>
<p>类似的情况也会有，比如根据值的变化，进行网络请求，根据值的变化进行组件的生成和销毁（我们经常成为这类操作为副作用）。把这类需求写在<code>watch</code>监听器里就是不错的选择。</p>
<p>在写代码之前，你可以删除前两节课学习生命周期时的钩子函数，让代码变得干净一些。</p>
<p>使用watch监听</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">  &lt;div&gt;&lt;button @click=&quot;overAction&quot;&gt;点餐完毕&lt;/button&gt;&lt;/div&gt;</span><br><span class="line">  &lt;div&gt;双大括号 overText 双大括号&lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; ref, reactive, toRefs, watch &#125; from &#x27;vue&#x27;</span><br><span class="line"></span><br><span class="line">interface DataProps &#123;</span><br><span class="line">  mans: string[]</span><br><span class="line">  selectMan: string</span><br><span class="line">  selectManFun: (index: number) =&gt; void</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    console.log(&#x27;1.开始创建组件 setup 函数&#x27;)</span><br><span class="line">    const data: DataProps = reactive(&#123;</span><br><span class="line">      mans: [&#x27;大脚&#x27;, &#x27;张三&#x27;, &#x27;李四&#x27;],</span><br><span class="line">      selectMan: &#x27;&#x27;,</span><br><span class="line">      selectManFun: (index: number) =&gt; &#123;</span><br><span class="line">        data.selectMan = data.mans[index]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    // 要显示在点餐完毕那里的变量</span><br><span class="line">    const overText = ref(&#x27;张三科技&#x27;)</span><br><span class="line">    const overAction = () =&gt; &#123;</span><br><span class="line">      overText.value = &#x27;点餐完成|&#x27; + overText.value</span><br><span class="line">      // 可以写成 document.title = overText.value 但是不是响应式的,使用watch</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    watch(overText, (newValue, oldValue) =&gt; &#123;</span><br><span class="line">      console.log(`newValue---$&#123;newValue&#125;`)</span><br><span class="line">      console.log(`oldValue---$&#123;oldValue&#125;`)</span><br><span class="line">      document.title = newValue</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    // 使用toRefs包装data</span><br><span class="line">    const refData = toRefs(data)</span><br><span class="line">    // 这个return作用是,如果有些变量没必要在模板中使用,就可以不用return</span><br><span class="line">    return &#123;</span><br><span class="line">      // 写完了也得暴露出去</span><br><span class="line">      // ... 是扩展运算符</span><br><span class="line">      ...refData,</span><br><span class="line">      overText,</span><br><span class="line">      overAction</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>watch后面的overText可以跟多个值(数组)</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">watch([overText,data.selectMan], <span class="function">(<span class="params">newValue, oldValue</span>) =&gt;</span> &#123;</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">`newValue---<span class="subst">$&#123;newValue&#125;</span>`</span>)</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">`oldValue---<span class="subst">$&#123;oldValue&#125;</span>`</span>)</span><br><span class="line">     <span class="built_in">document</span>.title = newValue</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>只是这样写会报错，错误是必须又getter方法或者对象什么的</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 可以在后面接上一个数组,</span></span><br><span class="line">watch([overText, <span class="function">() =&gt;</span> data.selectMan], <span class="function">(<span class="params">newValue, oldValue</span>) =&gt;</span> &#123;</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">`newValue---<span class="subst">$&#123;newValue&#125;</span>`</span>)</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">`oldValue---<span class="subst">$&#123;oldValue&#125;</span>`</span>)</span><br><span class="line">	<span class="comment">// 因为是数组了,给第一个</span></span><br><span class="line">	<span class="built_in">document</span>.title = newValue[<span class="number">0</span>]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>现在程序就可以正常运行了</p>
<p>有人会说Vue3不能监听<code>reactive</code>里边的值是不是一个Bug，我想说的这并不是Bug，而是为了保持和Vue2的一致性，</p>
<p>因为在Vue2中也时这种结果，解决方案是要么是ref或者这种get/set方法的形式。要么你你开启设置<code>watchOptions</code>的deep为true，也就是深度监听模式。</p>
<h4 id="Vue3中模块化介绍，时间模块例子"><a href="#Vue3中模块化介绍，时间模块例子" class="headerlink" title="Vue3中模块化介绍，时间模块例子"></a>Vue3中模块化介绍，时间模块例子</h4><p>Vue3.x版本最大的一个提升，就是有更好的重用机制，你可以把任何你想独立的模块独立出去。比如在上节课的基础上，加一个显示当前时间的功能(例如：17:30:20)。并且这个功能要在不同的页面进行反复调用。</p>
<p>先来看不重用的写法，也就是我们把程序直接写在<code>App.vue</code>这个组件里。这里你可以先顶一个<code>ref</code>变量<code>nowTime</code>,然后通过<code>getNowTime</code>的方法，让他可以显示并一直更新当前时间。最后在<code>return</code>里返回这个变量和方法。</p>
<h5 id="独立模块化"><a href="#独立模块化" class="headerlink" title="独立模块化"></a>独立模块化</h5><p>这个显示时间的方法，可能在其他页面中也会使用，所以现在的需求是把这个时间显示的功能进行模块和重用化。</p>
<p>可以在<code>src</code>目录下，新建一个文件夹<code>hooks</code>(所有抽离出来的功能模块都可以放到这个文件夹里)，然后再新建一个文件<code>useNowTime.ts</code>,这里使用<code>use</code>开头是一个使用习惯，代表是一个抽离出来的模块。</p>
<p>有了模块之后，我们就可以把写的代码复制到<code>useNowTime.ts</code>文件里了。然后进行必要的修改。</p>
<p>因为使用了ref，所以要引入</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> nowTime = ref(<span class="string">&#x27;00:00:00&#x27;</span>)</span><br><span class="line">  <span class="keyword">const</span> getNowTime = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="built_in">Date</span>()</span><br><span class="line">  <span class="comment">// 判断就是小于10就加一个0在前面，能好看点</span></span><br><span class="line">  <span class="keyword">const</span> hour = now.getHours() &lt; <span class="number">10</span> ? <span class="string">&#x27;0&#x27;</span> + now.getHours() : now.getHours()</span><br><span class="line">  <span class="keyword">const</span> minu = now.getMinutes() &lt; <span class="number">10</span> ? <span class="string">&#x27;0&#x27;</span> + now.getMinutes() : now.getMinutes()</span><br><span class="line">  <span class="keyword">const</span> sec = now.getSeconds() &lt; <span class="number">10</span> ? <span class="string">&#x27;0&#x27;</span> + now.getSeconds() : now.getSeconds()</span><br><span class="line">  nowTime.value = hour + <span class="string">&#x27;:&#x27;</span> + minu + <span class="string">&#x27;:&#x27;</span> + sec</span><br><span class="line">  <span class="built_in">setTimeout</span>(getNowTime, <span class="number">1000</span>) <span class="comment">//每一秒执行一次这个方法</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> &#123; nowTime, getNowTime &#125;</span><br></pre></td></tr></table></figure>

<p>在原本的App.vue中</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;script lang=<span class="string">&quot;ts&quot;</span>&gt;</span><br><span class="line"><span class="keyword">import</span> &#123; nowTime, getNowTime &#125; <span class="keyword">from</span> <span class="string">&#x27;./hooks/useNowTime&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&#x27;App&#x27;</span>,</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="comment">//....</span></span><br><span class="line">      nowTime,</span><br><span class="line">      getNowTime</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>现在可以看出这种方式，比vue2中要好很多，<strong>不用再使用<code>mixins</code>(混入)要好很多</strong>。(我连mixins都没看我人傻了)</p>
<p>我觉的这个算是Vue3.x一个非常重要的改进。</p>
<h5 id="模块化改进例子"><a href="#模块化改进例子" class="headerlink" title="模块化改进例子"></a>模块化改进例子</h5><p>比如我们要使用axios</p>
<p>里我们使用axios来进行远程随机获得图片，但是我们这里作的不是远程随机获得图片，而是模块化一个通用的远程调用API的组件，这个组件可以远程请求一个指定的URL，并且返回所得到的值。 先用<code>npm</code>的方式安装<code>axios</code>.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install axios --save</span><br></pre></td></tr></table></figure>

<p>这个的安装的时间会稍微有一点长。</p>
<p>在上节课的文件夹里，新建一个文件，叫做<code>useURLAxios.ts</code>,然后先引入<code>ref</code>和<code>axios</code>.在文件里写一个<code>useUrlAxios</code>方法，在方法里声明四个响应式变量<code>result</code>、<code>loading</code>、<code>loaded</code>和<code>error</code>。声明好后，使用<code>axios</code>进行访问远程链接。最后记得要进行<code>return</code>和<code>export default</code>。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; ref &#125; <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">userUrlAxios</span>(<span class="params">url: <span class="built_in">string</span></span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 结果,默认为null</span></span><br><span class="line">  <span class="keyword">const</span> result = ref(<span class="literal">null</span>)</span><br><span class="line">  <span class="comment">// 加载状态,默认true</span></span><br><span class="line">  <span class="keyword">const</span> loading = ref(<span class="literal">true</span>)</span><br><span class="line">  <span class="comment">// 已经加载完成了,刚开始肯定是没有加载完成的false</span></span><br><span class="line">  <span class="keyword">const</span> loaded = ref(<span class="literal">false</span>)</span><br><span class="line">  <span class="comment">// 错误信息显示给用户</span></span><br><span class="line">  <span class="keyword">const</span> error = ref(<span class="literal">null</span>)</span><br><span class="line"></span><br><span class="line">  axios.get(url).then(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span><br><span class="line">    loading.value = <span class="literal">false</span></span><br><span class="line">    loaded.value = <span class="literal">true</span></span><br><span class="line">    result.value = res.data</span><br><span class="line">  &#125;).catch(<span class="function"><span class="params">e</span> =&gt;</span> &#123;</span><br><span class="line">    error.value = e</span><br><span class="line">    <span class="comment">// 已经返回结果了虽然是错误的</span></span><br><span class="line">    loading.value = <span class="literal">false</span></span><br><span class="line">  &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> &#123; result, loading, loaded, error &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> userUrlAxios</span><br></pre></td></tr></table></figure>

<p>引入使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;h2&gt;欢迎光临洗脚中心&lt;/h2&gt;</span><br><span class="line">    &lt;div&gt;随机选择一位张三为你服务&lt;/div&gt;</span><br><span class="line">    &lt;div v-if=&quot;loading&quot;&gt;&lt;/div&gt;</span><br><span class="line">    &lt;img v-if=&quot;loaded&quot; :src=&quot;result.imgUrl&quot; /&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import userUrlAxios from &#x27;./hooks/userUrlAxios&#x27;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    const &#123; result, loading, loaded &#125; = userUrlAxios(&#x27;https://apiblog.jspang.com/default/getGirl&#x27;)</span><br><span class="line"></span><br><span class="line">    return &#123; result, loading, loaded &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h4 id="Teleport-瞬间移动函数的使用"><a href="#Teleport-瞬间移动函数的使用" class="headerlink" title="Teleport 瞬间移动函数的使用"></a>Teleport 瞬间移动函数的使用</h4><p><code>Teleport</code>在国内大部分都翻译成了瞬间移动组件，个人觉得不太好理解。我把这个函数叫独立组件，它可以把你写的组件挂载到任何你想挂载的DOM上，所以说是很自由很独立的。 在使用<code>Vue2</code>的时候是作不到的。</p>
<p>我们来写一个弹出框的组件</p>
<h5 id="编写弹出框的组件"><a href="#编写弹出框的组件" class="headerlink" title="编写弹出框的组件"></a>编写弹出框的组件</h5><p>在components文件夹内，创建Modal.vue</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div id=&quot;center&quot;&gt;</span><br><span class="line">    &lt;h2&gt;JSPang.com&lt;/h2&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style&gt;</span><br><span class="line">#center &#123;</span><br><span class="line">  width: 200px;</span><br><span class="line">  height: 200px;</span><br><span class="line">  border: 2px solid black;</span><br><span class="line">  background: white;</span><br><span class="line">  position: fixed;</span><br><span class="line">  left: 50%;</span><br><span class="line">  top: 50%;</span><br><span class="line">  margin-left: -100px;</span><br><span class="line">  margin-top: -100px;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>使用Modal组件</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> modal <span class="keyword">from</span> <span class="string">&#x27;./components/Modal.vue&#x27;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">components: &#123;</span><br><span class="line">  modal</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;modal&gt;&lt;/modal&gt;</span><br></pre></td></tr></table></figure>

<p>效果就是在页面中间多了块白色区域，里面写了JSPang.com</p>
<p><strong>F12开发者工具查看，组件是挂载到id=”app”上面的，而且挂载到app节点上还让我们的组件多了居中效果</strong></p>
<p>这样包裹遇到的问题</p>
<ol>
<li>Dialog被包裹在其它组件之中，容易被干扰</li>
<li>样式也在其它组件中，容易变得非常混乱</li>
</ol>
<p><strong>我们想让组件独立出来就用到了teleport</strong></p>
<h5 id="使用Teleport方法"><a href="#使用Teleport方法" class="headerlink" title="使用Teleport方法"></a>使用Teleport方法</h5><p><code>Teleport</code>方法，可以把<code>Dialog</code>组件渲染到你任意想渲染的外部Dom上，不必嵌套再<code>#app</code>里了，这样就不会互相干扰了。你可以把<code>Teleport</code>看成一个传送门，把你的组件传送到你需要的地方。 <code>teleport</code>组件和其它组件没有任何其它的差异，用起来都是一样的。</p>
<p>使用的第一步是把你编写的组件用<code>&lt;teleport&gt;</code>标签进行包裹，在组件上有一个<code>to</code>属性，这个就是要写你需要渲染的<code>DOM</code>ID了。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;teleport to=&quot;#modal&quot;&gt;</span><br><span class="line">    &lt;div id=&quot;center&quot;&gt;</span><br><span class="line">      &lt;h2&gt;JSPang11&lt;/h2&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  &lt;/teleport&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<p>然后我们在打开<code>/public/index.html</code>,增加一个<code>model</code>节点。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</span><br><span class="line">&lt;div id=&quot;modal&quot;&gt;&lt;/div&gt;</span><br></pre></td></tr></table></figure>

<p>这时候在浏览器中预览，就会发现，现在组件已经挂载到<code>model</code>节点上了，这就是<code>teleport</code>组件的使用了。</p>
<h4 id="Supense-初识异步请求组件"><a href="#Supense-初识异步请求组件" class="headerlink" title="Supense 初识异步请求组件"></a>Supense 初识异步请求组件</h4><p>在前端开发中，异步请求组件必不可少。比如读取远程图片，比如调用后台接口，这些都需要异步请求。</p>
<p>在Vue2.x时代，判断异步请求的状态是一件必须的事情，但是这些状态都要自己处理，根据请求是否完毕展示不同的界面。</p>
<p>尤大神深知民间饥苦，在Vue3.x中给我们提供了<code>Suspense</code>组件。这节课我们就先简单学习一下。</p>
<h5 id="编写AsyncShow-vue自定义组件"><a href="#编写AsyncShow-vue自定义组件" class="headerlink" title="编写AsyncShow.vue自定义组件"></a>编写AsyncShow.vue自定义组件</h5><p>在随机选择服务菜单那节中，已经作了一个异步请求的组件，并且是简单处理了请求状态的。学会<code>Suspense</code>之后，就不用自己手写这些业务逻辑处理请求状态了，<code>Suspense</code>提供两个template的位置，一个是没有请求回来时显示的内容，一个是全部请求完毕的内容。这样进行异步内容的渲染就会非常简单。</p>
<p><strong>注意点:如果你要使用<code>Suspense</code>的话，要返回一个promise对象，而不是原来的那种<code>JSON</code>对象。</strong></p>
<p>我们先用一个例子来感受一下,我们先来写一个组件，在<code>components</code>文件夹下边，新建一个<code>AsyncShow.vue</code>文件，然后边下代码如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;h1&gt;双大括号 result 双大括号&lt;/h1&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">// 解决在ts下无法正确提示参数的问题,原来的方式有些没有提示</span><br><span class="line">import &#123; defineComponent &#125; from &#x27;vue&#x27;</span><br><span class="line">export default defineComponent(&#123;</span><br><span class="line">  setup() &#123;</span><br><span class="line">    return new Promise((resolve, reject) =&gt; &#123;</span><br><span class="line">      setTimeout(() =&gt; &#123;</span><br><span class="line">        return resolve(&#123; result: &#x27;JSPang&#x27; &#125;)</span><br><span class="line">      &#125;, 2000)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><code>defineComponent</code>是用来解决TypeScript情况下，传统的<code>Vue.extends</code>无法对组件给出正确的参数类型推断的。也就是说在TypeScript环境中如果参数类型推断不正常时，用<code>defineComponent()</code>组件来进行包装函数。</p>
<p>然后我们<code>new</code>了一个<code>Promise</code>对象，然后用<code>setTimeout</code>等待两秒后返回<code>JSPang</code>文字就可以了。</p>
<p>在App.vue中使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;Suspense&gt;</span><br><span class="line">      &lt;!--请求结束回来的 --&gt;</span><br><span class="line">      &lt;template #default&gt;</span><br><span class="line">        &lt;async-show&gt;&lt;/async-show&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">      &lt;!--一没有请求结束回来的 --&gt;</span><br><span class="line">      &lt;template #fallback&gt;</span><br><span class="line">        &lt;h1&gt;Loading....&lt;/h1&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">    &lt;/Suspense&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import AsyncShow from &#x27;./components/AsyncShow.vue&#x27;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;App&#x27;,</span><br><span class="line">  components: &#123;</span><br><span class="line">    AsyncShow</span><br><span class="line">  &#125;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    return &#123;&#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>可以看到<code>Suspense</code>是有两个<code>template</code>插槽的，第一个<code>default</code>代表异步请求完成后，显示的模板内容。<code>fallback</code>代表在加载中时，显示的模板内容。</p>
<p>页面上的效果是：首先显示loading….，两秒后显示JSPang</p>
<h5 id="Suspense-深入学习，真实请求"><a href="#Suspense-深入学习，真实请求" class="headerlink" title="Suspense 深入学习，真实请求"></a>Suspense 深入学习，真实请求</h5><p>上节课我们是一个假的异步请求，利用了<code>setTimeOut()</code>方法来模拟异步请求，当然这也很恰当的演示了<code>Suspense</code>的使用方法。这节课我们就深入一下，用以前请求象牙山三大美女的API真实接口来继续深入学习一下。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">随机图片API：https://apiblog.jspang.com/default/getGirl</span><br></pre></td></tr></table></figure>

<h6 id="编写随机图片的异步组件"><a href="#编写随机图片的异步组件" class="headerlink" title="编写随机图片的异步组件"></a>编写随机图片的异步组件</h6><p>在<code>/src/components/</code>目录下，新建一个<code>GirlShow.vue</code>的新组件。</p>
<p>我们先来写个基本的模板，其实你可以把这段代码复制进你的程序，因为这段代码你一定打过很多遍了。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line">import &#123; defineComponent &#125; from &#x27;vue&#x27;</span><br><span class="line">    </span><br><span class="line">export default defineComponent(&#123;</span><br><span class="line">    setup() &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>再向下写，需要注意的是，上节课的例子，我们返回的是一个<code>promise</code>对象，其实我个人是不喜欢<code>promise</code>这种写法的，我更喜欢用<code>async...await</code>的写法，它是<code>promise</code>的语法糖。建议你在工作中也尽量的使用<code>async...await</code>的写法。</p>
<p><code>Suspense</code>也是支持<code>async...await</code>的语法的，所以这个组件就用<code>async</code>的写法来写。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">    &lt;img :src=&quot;result &amp;&amp; result.imgUrl&quot;  /&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import axios from &#x27;axios&#x27;</span><br><span class="line">import &#123; defineComponent &#125; from &#x27;vue&#x27;</span><br><span class="line">export default defineComponent(&#123;</span><br><span class="line">    async setup() &#123;  //promise 语法糖  返回之后也是promise对象</span><br><span class="line">        const rawData = await  axios.get(&#x27;https://apiblog.jspang.com/default/getGirl&#x27;)</span><br><span class="line">        return &#123;result:rawData.data&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>这样组件就编写完成了，看起来是比纯<code>Promise</code>的写法好看很多了。</p>
<h6 id="引入并使用Suspense组件"><a href="#引入并使用Suspense组件" class="headerlink" title="引入并使用Suspense组件"></a>引入并使用Suspense组件</h6><p>打开<code>App.vue</code>页面，然后先用<code>import</code>引入<code>GirlShow.vue</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> GirlShow <span class="keyword">from</span> <span class="string">&quot;./components/GirlShow.vue&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>然后在<code>components</code>中声明一下，就可以在模板中使用了</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> app = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&quot;App&quot;</span>,</span><br><span class="line">  <span class="attr">components</span>: &#123; AsyncShow, GirlShow &#125;,</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;&#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>模板部分代码。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;Suspense&gt;</span><br><span class="line">      &lt;template #default&gt;</span><br><span class="line">         &lt;girl-show /&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">      &lt;template #fallback&gt;</span><br><span class="line">        &lt;h1&gt;Loading...&lt;/h1&gt;</span><br><span class="line">      &lt;/template&gt;</span><br><span class="line">    &lt;/Suspense&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure>

<p>这部分写完，就可以打开服务<code>yarn serve</code>，然后到<code>http://localhost:8080/</code>预览一下结果哦。注意，我的服务器设置了缓存，所以你可能几次刷新都会是同一张照片，这个不是你的问题。但你也要注意，自己是不是也有图片缓存。</p>
<h6 id="处理异步请求错误"><a href="#处理异步请求错误" class="headerlink" title="处理异步请求错误"></a>处理异步请求错误</h6><p>在异步请求中必须要作的一件事情，就是要捕获错误，因为我们没办法后端给我们返回的结果，也有可能服务不通，所以一定要进行捕获异常和进行处理。</p>
<p>在<code>vue3.x</code>的版本中，可以使用<code>onErrorCaptured</code>这个钩子函数来捕获异常。在使用这个钩子函数前，需要先进行引入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; ref , onErrorCaptured&#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>有了<code>onErrorCaptured</code>就可以直接在<code>setup()</code>函数中直接使用了。钩子函数要求我们返回一个布尔值，代表错误是否向上传递，我们这里返回了<code>true</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> app = &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="string">&quot;App&quot;</span>,</span><br><span class="line">  <span class="attr">components</span>: &#123; AsyncShow, GirlShow &#125;,</span><br><span class="line">  <span class="function"><span class="title">setup</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    onErrorCaptured(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">`error====&gt;`</span>,error)</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span>  </span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> &#123;&#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>写好后，我们故意把请求地址写错，然后打开浏览器的终端，看一下控制台已经捕获到错误了。在实际工作中，你可以根据你的真实需求，处理这些错误。我这里就不做过多的演示啦。</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/HC2MwV"><img src="https://s4.ax1x.com/2022/01/30/HC2MwV.png" class="lazyload" data-srcset="https://s4.ax1x.com/2022/01/30/HC2MwV.png" srcset="" alt="HC2MwV.png"></a></p>

  
  
  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/blog/JavaAnnotation.html'>
          <p class='title'><i class="fas fa-chevron-left" aria-hidden="true"></i>注解</p>
          <p class='content'>1.注解Java Annotation笔记来自：Java SE——注解和反射-KuangStudy-文章
框架底层都是注解和反射
1.注解入门
Annotation是jdk1.5开始引入的新技术...</p>
        </a>
      
      
        <a class='next' href='/blog/computernet.html'>
          <p class='title'>计算机网络简答题<i class="fas fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>一写出多个应用层的协议及对应的端口号，以及再传输层交给TCP还是UDP


协议动态主机配置协议
端口号
传输层



动态主机配置协议 DHCP
端口号68
(UDP)


域名系统DNS
端...</p>
        </a>
      
    </div>
  
</article>


  

  <article class="post white-box reveal shadow" id="comments">
    <p ct><i class='fas fa-comments'></i> 评论</p>
    
    <div id="valine_container" class="valine_thread">
  <i class="fas fa-cog fa-spin fa-fw fa-2x"></i>
</div>

  </article>






</div>
<aside class='l_side'>
  
  
    
    



  <section class="widget toc-wrapper shadow desktop mobile" id="toc-div" >
    
  <header>
    
      <i class="fas fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#Webpack"><span class="toc-text">Webpack</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%EF%BC%9Awebpack%E8%83%BD%E5%90%A6%E8%A7%A3%E5%86%B3%E9%AB%98%E7%BA%A7%E8%AF%AD%E6%B3%95%EF%BC%9F"><span class="toc-text">问题：webpack能否解决高级语法？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Webpack%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">Webpack的基本使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%A3%E7%A0%81%E5%8E%8B%E7%BC%A9"><span class="toc-text">代码压缩</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%93%E5%8C%85%E7%9A%84%E5%85%A5%E5%8F%A3%E5%92%8C%E5%87%BA%E5%8F%A3"><span class="toc-text">自定义打包的入口和出口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%97%AE%E9%A2%98%EF%BC%9A%E6%AF%8F%E6%AC%A1%E4%BF%AE%E6%94%B9%E6%BA%90%E4%BB%A3%E7%A0%81%E9%83%BD%E8%A6%81%E6%89%93%E5%8C%85%E4%B8%80%E6%AC%A1%EF%BC%9F"><span class="toc-text">问题：每次修改源代码都要打包一次？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack-dev-server%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE"><span class="toc-text">webpack-dev-server安装和配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%B0%E5%BD%95%E4%B8%80%E4%B8%AA%E6%8A%A5%E9%94%99"><span class="toc-text">记录一个报错</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack-dev-server%E7%9A%84%E6%8A%A5%E9%94%99"><span class="toc-text">webpack-dev-server的报错</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack-dev-server%E5%90%AF%E5%8A%A8%E5%90%8E%E6%97%A0%E6%B3%95%E5%AE%9E%E6%97%B6%E6%9B%B4%E6%96%B0%E9%A1%B5%E9%9D%A2"><span class="toc-text">webpack-dev-server启动后无法实时更新页面</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#html-webpack-plugin"><span class="toc-text">html-webpack-plugin</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#doServer%E8%8A%82%E7%82%B9"><span class="toc-text">doServer节点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack%E4%B8%AD%E7%9A%84%E6%8F%92%E4%BB%B6"><span class="toc-text">webpack中的插件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack%E4%B8%AD%E7%9A%84loader"><span class="toc-text">webpack中的loader</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#loader%E6%A6%82%E8%BF%B0"><span class="toc-text">loader概述</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#webpack%E6%89%93%E5%8C%85%E5%A4%84%E7%90%86css%E6%96%87%E4%BB%B6"><span class="toc-text">webpack打包处理css文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#less%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%84%E7%90%86%E6%96%B9%E5%BC%8F"><span class="toc-text">less的文件处理方式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%89%93%E5%8C%85%E5%A4%84%E7%90%86%E6%A0%B7%E5%BC%8F%E8%A1%A8%E4%B8%AD%E4%B8%8Eurl%E8%B7%AF%E5%BE%84%E7%9B%B8%E5%85%B3%E7%9A%84%E6%96%87%E4%BB%B6"><span class="toc-text">打包处理样式表中与url路径相关的文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E5%8A%A0%E8%BD%BD%E5%9B%BE%E7%89%87%E7%9A%84loader"><span class="toc-text">配置加载图片的loader</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A9%E7%94%A8babel-loader%E8%BD%AC%E6%8D%A2%E5%A4%84%E7%90%86%E9%AB%98%E7%BA%A7%E7%9A%84JS%E8%AF%AD%E6%B3%95"><span class="toc-text">利用babel-loader转换处理高级的JS语法</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%93%E5%8C%85%E5%8F%91%E5%B8%83"><span class="toc-text">打包发布</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%9A%84js%E6%96%87%E4%BB%B6"><span class="toc-text">配置自动生成的js文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E5%9B%BE%E7%89%87%E7%94%9F%E6%88%90%E8%B7%AF%E5%BE%84"><span class="toc-text">配置图片生成路径</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E8%87%AA%E5%8A%A8%E5%88%A0%E9%99%A4dist"><span class="toc-text">配置自动删除dist</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#webpack%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E7%9F%A5%E8%AF%86%E7%82%B9SourceMap"><span class="toc-text">webpack最后一个知识点SourceMap</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SourceMap%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5"><span class="toc-text">SourceMap的最佳实践</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#ES6%E9%BB%98%E8%AE%A4%E7%9A%84%E5%AF%BC%E5%87%BA%E6%96%B9%E5%BC%8F"><span class="toc-text">ES6默认的导出方式</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%89%E8%A3%85VUE%E6%B5%8F%E8%A7%88%E5%99%A8%E8%B0%83%E8%AF%95%E5%B7%A5%E5%85%B7"><span class="toc-text">安装VUE浏览器调试工具</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8Vue-js-devtools"><span class="toc-text">使用Vue.js devtools</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Vue%E7%A6%81%E7%94%A8devtools"><span class="toc-text">Vue禁用devtools</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%97%AE%E9%A2%98"><span class="toc-text">问题</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#VUE%E7%AE%80%E4%BB%8B"><span class="toc-text">VUE简介</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8%E8%A7%86%E5%9B%BE"><span class="toc-text">数据驱动视图</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8F%8C%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A"><span class="toc-text">双向数据绑定</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#MVVM"><span class="toc-text">MVVM</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8%E6%AD%A5%E9%AA%A4"><span class="toc-text">基本使用步骤</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Vue%E7%9A%84%E6%8C%87%E4%BB%A4%E5%92%8C%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">Vue的指令和过滤器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E5%86%85%E5%AE%B9%E6%B8%B2%E6%9F%93%E6%8C%87%E4%BB%A4"><span class="toc-text">1.内容渲染指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#v-text"><span class="toc-text">v-text</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8F%8C%E5%A4%A7%E6%8B%AC%E5%8F%B7-%E5%8F%8C%E5%A4%A7%E6%8B%AC%E5%8F%B7%E8%AF%AD%E6%B3%95%EF%BC%88%E6%8F%92%E5%80%BC%EF%BC%89"><span class="toc-text">双大括号 双大括号语法（插值）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#v-html"><span class="toc-text">v-html</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E5%B1%9E%E6%80%A7%E7%BB%91%E5%AE%9A%E6%8C%87%E4%BB%A4"><span class="toc-text">2.属性绑定指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#v-bind"><span class="toc-text">v-bind</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8F%92%E5%80%BC%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E8%BF%90%E7%AE%97"><span class="toc-text">插值表达式的运算</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E6%8C%87%E4%BB%A4"><span class="toc-text">3.事件绑定指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E5%AF%B9%E8%B1%A1e%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">事件对象e的使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E4%BF%AE%E9%A5%B0%E7%AC%A6"><span class="toc-text">事件修饰符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-%E6%8C%89%E9%92%AE%E4%BF%AE%E9%A5%B0%E7%AC%A6"><span class="toc-text">4.按钮修饰符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-%E5%8F%8C%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A%E6%8C%87%E4%BB%A4"><span class="toc-text">5.双向数据绑定指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-%E6%9D%A1%E4%BB%B6%E6%B8%B2%E6%9F%93%E6%8C%87%E4%BB%A4"><span class="toc-text">6.条件渲染指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#vue%E7%9A%84%E6%8C%87%E4%BB%A4%E5%92%8C%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">vue的指令和过滤器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-%E5%88%97%E8%A1%A8%E6%B8%B2%E6%9F%93%E6%8C%87%E4%BB%A4"><span class="toc-text">7.列表渲染指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A1%A8%E6%A0%BC%E7%BB%BC%E5%90%88%E6%A1%88%E4%BE%8B"><span class="toc-text">表格综合案例</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-vue2%E4%B8%AD%E7%9A%84%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">8.vue2中的过滤器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2%E7%A7%81%E6%9C%89%E8%BF%87%E6%BB%A4%E5%99%A8%E5%92%8C%E5%85%A8%E5%B1%80%E8%BF%87%E6%BB%A4%E5%99%A8"><span class="toc-text">8.2私有过滤器和全局过滤器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3%E8%BF%87%E6%BB%A4%E5%99%A8%E7%9A%84%E5%8F%82%E6%95%B0"><span class="toc-text">8.3过滤器的参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-%E4%BE%A6%E5%90%AC%E5%99%A8Watch"><span class="toc-text">9.侦听器Watch</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BE%A6%E5%90%AC%E5%99%A8%E7%9A%84%E5%AE%9A%E4%B9%89%E6%A0%BC%E5%BC%8F"><span class="toc-text">侦听器的定义格式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B7%B1%E5%BA%A6%E4%BE%A6%E5%90%AC"><span class="toc-text">深度侦听</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7"><span class="toc-text">计算属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ES6-%E6%A8%A1%E6%9D%BF%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">ES6 - 模板字符串</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Axios"><span class="toc-text">Axios</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#axios%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0"><span class="toc-text">axios传递参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ES6-%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC"><span class="toc-text">ES6 - 解构赋值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#axios-get%E5%92%8Caxios-post"><span class="toc-text">axios.get和axios.post</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8D%95%E9%A1%B5%E9%9D%A2%E5%BA%94%E7%94%A8"><span class="toc-text">单页面应用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95%E5%90%84%E4%B8%AA%E6%96%87%E4%BB%B6"><span class="toc-text">项目目录各个文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#vue%E9%A1%B9%E7%9B%AE%E7%9A%84%E8%BF%90%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-text">vue项目的运行流程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Vue%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91"><span class="toc-text">Vue组件开发</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E7%88%B6%E5%AD%90%E5%85%B3%E7%B3%BB"><span class="toc-text">Vue组件之间的父子关系</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue%E4%BD%BF%E7%94%A8%E7%BB%84%E4%BB%B6"><span class="toc-text">Vue使用组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue%E5%85%A8%E5%B1%80%E7%BB%84%E4%BB%B6"><span class="toc-text">Vue全局组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E7%9A%84props"><span class="toc-text">组件的props</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#props%E7%9A%84default%E9%BB%98%E8%AE%A4%E5%80%BC"><span class="toc-text">props的default默认值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#props%E7%9A%84type%E7%B1%BB%E5%9E%8B"><span class="toc-text">props的type类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#props%E7%9A%84required%E5%BF%85%E5%A1%AB%E9%A1%B9"><span class="toc-text">props的required必填项</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E6%A0%B7%E5%BC%8F%E5%86%B2%E7%AA%81%E9%97%AE%E9%A2%98"><span class="toc-text">组件之间的样式冲突问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%AC%AC%E4%B8%89%E6%96%B9%E6%8F%92%E4%BB%B6%E7%9A%84%E6%A0%B7%E5%BC%8F%E5%A4%84%E7%90%86"><span class="toc-text">第三方插件的样式处理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#vue%E6%96%87%E4%BB%B6%E7%9A%84%E8%BF%90%E8%A1%8C%E5%8E%9F%E7%90%86"><span class="toc-text">vue文件的运行原理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">组件的生命周期</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%87%BD%E6%95%B0"><span class="toc-text">组件的生命周期函数</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E5%88%9B%E5%BB%BA%E9%98%B6%E6%AE%B5"><span class="toc-text">组件创建阶段</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E8%BF%90%E8%A1%8C%E9%98%B6%E6%AE%B5"><span class="toc-text">组件运行阶段</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E9%94%80%E6%AF%81%E9%98%B6%E6%AE%B5"><span class="toc-text">组件销毁阶段</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="toc-text">组件之间的关系</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="toc-text">1.组件之间的关系</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E6%95%B0%E6%8D%AE%E5%85%B1%E4%BA%AB"><span class="toc-text">2.父子组件之间的数据共享</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-1-%E7%88%B6%E7%BB%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BC%A0%E6%95%B0%E6%8D%AE"><span class="toc-text">2.1.父组件向子组件传数据</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-2-%E5%AD%90%E7%BB%84%E4%BB%B6%E5%90%91%E7%88%B6%E7%BB%84%E4%BB%B6%E4%BC%A0%E6%95%B0%E6%8D%AE"><span class="toc-text">2.2.子组件向父组件传数据</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%85%84%E5%BC%9F%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E4%BC%A0%E9%80%92%E5%80%BC"><span class="toc-text">3.兄弟组件之间传递值</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8ref%E5%BC%95%E7%94%A8DOM%E5%85%83%E7%B4%A0"><span class="toc-text">使用ref引用DOM元素</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ref%E5%BC%95%E7%94%A8%E7%BB%84%E4%BB%B6%E5%AE%9E%E4%BE%8B"><span class="toc-text">ref引用组件实例</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0%E6%8C%89%E9%92%AE%E6%8E%A7%E5%88%B6%E8%BE%93%E5%85%A5%E6%A1%86%E7%9A%84%E6%98%BE%E7%A4%BA"><span class="toc-text">实现按钮控制输入框的显示</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#this-nextTick-cb-%E6%96%B9%E6%B3%95"><span class="toc-text">this.$nextTick(cb)方法</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B4%AD%E7%89%A9%E8%BD%A6%E6%A1%88%E4%BE%8B"><span class="toc-text">购物车案例</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E7%9A%84some%E6%96%B9%E6%B3%95"><span class="toc-text">数组的some方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E7%9A%84every%E6%96%B9%E6%B3%95"><span class="toc-text">数组的every方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E7%9A%84reduce%E6%96%B9%E6%B3%95"><span class="toc-text">数组的reduce方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%B4%AD%E7%89%A9%E8%BD%A6%E6%A1%88%E4%BE%8B%E5%AE%9E%E7%8E%B0%E6%AD%A5%E9%AA%A4"><span class="toc-text">购物车案例实现步骤</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B8%B2%E6%9F%93Goods%E7%BB%84%E4%BB%B6"><span class="toc-text">渲染Goods组件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%A4%8D%E9%80%89%E6%A1%86%E6%93%8D%E4%BD%9C%E6%9B%B4%E6%94%B9%E5%AF%B9%E5%BA%94%E6%95%B0%E6%8D%AE%E9%A1%B9"><span class="toc-text">复选框操作更改对应数据项</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%88%97%E8%A1%A8%E5%A4%8D%E9%80%89%E6%A1%86%E7%9A%84bug"><span class="toc-text">列表复选框的bug</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%BB%93%E7%AE%97%E4%BB%98%E6%AC%BE%E7%BB%84%E4%BB%B6Footer"><span class="toc-text">结算付款组件Footer</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9C%A8Goods%E7%BB%84%E4%BB%B6%E4%B8%AD%E4%BD%BF%E7%94%A8Count%E7%BB%84%E4%BB%B6"><span class="toc-text">在Goods组件中使用Count组件</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E7%BB%84%E4%BB%B6"><span class="toc-text">动态组件</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Keep-Alive%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">Keep-Alive的使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#keep-alive%E7%9A%84include%E5%B1%9E%E6%80%A7"><span class="toc-text">keep-alive的include属性</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8F%92%E6%A7%BD"><span class="toc-text">插槽</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%85%B7%E5%90%8D%E6%8F%92%E6%A7%BD%E7%9A%84%E5%AE%9A%E4%B9%89%E5%92%8C%E4%BD%BF%E7%94%A8"><span class="toc-text">具名插槽的定义和使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%8F%92%E6%A7%BD"><span class="toc-text">作用域插槽</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9F%BA%E4%BA%8E%E6%8F%92%E6%A7%BD%E5%AF%B9%E8%B4%AD%E7%89%A9%E8%BD%A6%E6%A1%88%E4%BE%8B%E8%BF%9B%E8%A1%8C%E4%BF%AE%E6%94%B9"><span class="toc-text">基于插槽对购物车案例进行修改</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4"><span class="toc-text">自定义指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%A7%81%E6%9C%89%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4"><span class="toc-text">私有自定义指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#bind%E5%87%BD%E6%95%B0"><span class="toc-text">bind函数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#update%E5%87%BD%E6%95%B0"><span class="toc-text">update函数</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%85%A8%E5%B1%80%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4"><span class="toc-text">全局自定义指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ESLint"><span class="toc-text">ESLint</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AEvscode%E7%9A%84ESLint"><span class="toc-text">配置vscode的ESLint</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B0%81%E8%A3%85Axios"><span class="toc-text">封装Axios</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BC%BA%E7%82%B9"><span class="toc-text">缺点</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B7%AF%E7%94%B1"><span class="toc-text">路由</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#vue-router"><span class="toc-text">vue-router</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9C%A8%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%AE%89%E8%A3%85vue-router"><span class="toc-text">在项目中安装vue-router</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%9B%E5%BB%BA%E8%B7%AF%E7%94%B1%E6%A8%A1%E5%9D%97"><span class="toc-text">创建路由模块</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%B7%AF%E7%94%B1%E9%87%8D%E5%AE%9A%E5%90%91"><span class="toc-text">路由重定向</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B5%8C%E5%A5%97%E8%B7%AF%E7%94%B1"><span class="toc-text">嵌套路由</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%8C%B9%E9%85%8D"><span class="toc-text">动态路由匹配</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8F%82%E6%95%B0%E9%A1%B9"><span class="toc-text">参数项</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AF%BC%E8%88%AA"><span class="toc-text">导航</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AF%BC%E8%88%AA%E5%AE%88%E5%8D%AB"><span class="toc-text">导航守卫</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB"><span class="toc-text">1.全局前置守卫</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%AE%88%E5%8D%AB%E6%96%B9%E6%B3%95%E7%9A%84%E4%B8%89%E4%B8%AA%E5%BD%A2%E5%8F%82"><span class="toc-text">2.守卫方法的三个形参</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#admin%E5%90%8E%E5%8F%B0%E6%A1%88%E4%BE%8B"><span class="toc-text">admin后台案例</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A8%A1%E6%8B%9F%E7%99%BB%E5%BD%95"><span class="toc-text">模拟登录</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#token%E8%AE%A4%E8%AF%81%E6%97%B6%E7%9A%84%E8%AE%A4%E8%AF%81%E6%A0%BC%E5%BC%8F"><span class="toc-text">token认证时的认证格式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0%E9%80%80%E5%87%BA%E5%8A%9F%E8%83%BD"><span class="toc-text">实现退出功能</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%82%B9%E5%87%BB%E4%BE%A7%E8%BE%B9%E6%A0%8F%E6%8C%89%E9%92%AE%EF%BC%8C%E5%B1%95%E7%A4%BA%E4%B8%BB%E4%BD%93"><span class="toc-text">点击侧边栏按钮，展示主体</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B8%B2%E6%9F%93user%E9%A1%B5%E9%9D%A2%E7%9A%84%E6%95%B0%E6%8D%AE"><span class="toc-text">渲染user页面的数据</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%B4%E6%9D%A1%E6%A1%88%E4%BE%8B"><span class="toc-text">头条案例</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AEVant%E7%BB%84%E4%BB%B6%E5%BA%93"><span class="toc-text">安装和配置Vant组件库</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%89%E8%A3%85"><span class="toc-text">安装</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BC%95%E5%85%A5"><span class="toc-text">引入</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8"><span class="toc-text">使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8Tabbar%E6%A0%8F"><span class="toc-text">使用Tabbar栏</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9F%BA%E7%A1%80%E7%94%A8%E6%B3%95"><span class="toc-text">基础用法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#NavBar%E5%AF%BC%E8%88%AA%E6%A0%8F"><span class="toc-text">NavBar导航栏</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3navbar%E5%92%8Ctabbar%E9%81%AE%E6%8C%A1%E5%86%85%E5%AE%B9%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">解决navbar和tabbar遮挡内容的问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%96%87%E7%AB%A0%E5%88%97%E8%A1%A8%E6%95%B0%E6%8D%AE%E6%8E%A5%E5%8F%A3"><span class="toc-text">文章列表数据接口</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%AF%B7%E6%B1%82%E6%96%B9%E5%BC%8F"><span class="toc-text">请求方式</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%AF%B7%E6%B1%82%E6%A0%B9%E8%B7%AF%E5%BE%84"><span class="toc-text">请求根路径</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%AF%B7%E6%B1%82URL-%E5%9C%B0%E5%9D%80"><span class="toc-text">请求URL 地址</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%9F%A5%E8%AF%A2%E5%8F%82%E6%95%B0"><span class="toc-text">查询参数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%93%8D%E5%BA%94%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84"><span class="toc-text">响应的数据结构</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%BF%94%E5%9B%9E%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="toc-text">返回参数说明</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B0%81%E8%A3%85request%E5%8F%AF%E5%A4%8D%E7%94%A8%E7%9A%84%E6%A8%A1%E5%9D%97"><span class="toc-text">封装request可复用的模块</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B0%81%E8%A3%85Home%E7%BB%84%E4%BB%B6%E5%B0%81%E8%A3%85initArticleList%E6%96%B9%E6%B3%95"><span class="toc-text">封装Home组件封装initArticleList方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B0%81%E8%A3%85%E6%96%87%E7%AB%A0%E7%BB%84%E4%BB%B6"><span class="toc-text">封装文章组件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD%E6%9B%B4%E5%A4%9A%E6%95%B0%E6%8D%AE"><span class="toc-text">上拉加载更多数据</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#Vant%E7%9A%84List%E7%BB%84%E4%BB%B6"><span class="toc-text">Vant的List组件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD"><span class="toc-text">上拉加载</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0%E6%95%B0%E6%8D%AE"><span class="toc-text">下拉刷新数据</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vant%E5%AE%9A%E5%88%B6%E4%B8%BB%E9%A2%98"><span class="toc-text">Vant定制主题</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%AD%A5%E9%AA%A4%E4%B8%80-%E5%BC%95%E5%85%A5%E6%A0%B7%E5%BC%8F%E6%BA%90%E6%96%87%E4%BB%B6"><span class="toc-text">步骤一 引入样式源文件</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%A1%B9%E7%9B%AE%E6%89%93%E5%8C%85"><span class="toc-text">项目打包</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%A1%B9%E7%9B%AE%E6%A1%88%E4%BE%8B%E7%9A%84%E5%B0%8F%E4%BF%AE%E6%94%B9"><span class="toc-text">项目案例的小修改</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ES6%E6%A8%A1%E5%9D%97%E5%8C%96%E5%92%8C%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B"><span class="toc-text">ES6模块化和异步编程</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#ES6%E6%A8%A1%E5%9D%97%E5%8C%96"><span class="toc-text">ES6模块化</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%A8%A1%E5%9D%97%E5%8C%96%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95"><span class="toc-text">模块化基本语法</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Promise"><span class="toc-text">Promise</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9B%9E%E8%B0%83%E5%9C%B0%E7%8B%B1"><span class="toc-text">回调地狱</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3"><span class="toc-text">如何解决</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#Promise%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5"><span class="toc-text">Promise基本概念</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9F%BA%E4%BA%8E%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E6%8C%89%E9%A1%BA%E5%BA%8F%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9"><span class="toc-text">基于回调函数按顺序读取文件内容</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9F%BA%E4%BA%8Ethen-fs%E6%9D%A5%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9"><span class="toc-text">基于then-fs来读取文件内容</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#then-%E6%96%B9%E6%B3%95%E7%9A%84%E7%89%B9%E6%80%A7"><span class="toc-text">.then()方法的特性</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%80%9A%E8%BF%87-catch%E6%8D%95%E8%8E%B7%E9%94%99%E8%AF%AF"><span class="toc-text">通过.catch捕获错误</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#Promise-all-%E6%96%B9%E6%B3%95"><span class="toc-text">Promise.all()方法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#Promise-race-%E6%96%B9%E6%B3%95"><span class="toc-text">Promise.race()方法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9F%BA%E4%BA%8EPromise%E5%B0%81%E8%A3%85%E4%B8%80%E4%B8%AA%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6%E7%9A%84%E6%96%B9%E6%B3%95"><span class="toc-text">基于Promise封装一个读取文件的方法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%88%9B%E5%BB%BA%E5%85%B7%E4%BD%93%E7%9A%84%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C"><span class="toc-text">创建具体的异步操作</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%8E%B7%E5%8F%96-then%E4%B8%A4%E4%B8%AA%E5%BD%A2%E5%8F%82"><span class="toc-text">获取.then两个形参</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%B0%83%E7%94%A8resolve%E5%92%8Creject%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0"><span class="toc-text">调用resolve和reject回调函数</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#async-await"><span class="toc-text">async&#x2F;await</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#async-await%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">async&#x2F;await基本使用</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#async-await%E7%9A%84%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">async&#x2F;await的使用注意事项</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#EventLoop"><span class="toc-text">EventLoop</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%90%8C%E6%AD%A5%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1"><span class="toc-text">同步任务和异步任务</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%90%8C%E6%AD%A5%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B"><span class="toc-text">3.同步任务和异步任务的执行过程</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-EventLoop%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5"><span class="toc-text">4.EventLoop的基本概念</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%8F%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BE%AE%E4%BB%BB%E5%8A%A1"><span class="toc-text">宏任务和微任务</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E5%AE%8F%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BE%AE%E4%BB%BB%E5%8A%A1"><span class="toc-text">什么是宏任务和微任务</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%AE%8F%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BE%AE%E4%BB%BB%E5%8A%A1%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F"><span class="toc-text">宏任务和微任务的执行顺序</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#API%E6%8E%A5%E5%8F%A3%E6%A1%88%E4%BE%8B"><span class="toc-text">API接口案例</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0%E6%AD%A5%E9%AA%A4"><span class="toc-text">实现步骤</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%90%AD%E5%BB%BA%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84"><span class="toc-text">搭建项目的基本结构</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8try-catch%E6%8D%95%E8%8E%B7%E5%BC%82%E5%B8%B8"><span class="toc-text">使用try_catch捕获异常</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#vue3"><span class="toc-text">vue3</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#vue3%E7%9A%84%E6%96%B0%E7%89%B9%E6%80%A7"><span class="toc-text">vue3的新特性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue-cli%E6%9E%84%E5%BB%BA%E9%A1%B9%E7%9B%AE"><span class="toc-text">Vue-cli构建项目</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%9A%84%E4%B8%8D%E4%B8%80%E6%A0%B7"><span class="toc-text">Vue3生命周期的不一样</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue3%E4%B8%AD%E7%9A%84setup-%E5%92%8Cref-%E5%87%BD%E6%95%B0%E5%88%B6%E4%BD%9C%E7%82%B9%E9%A4%90%E4%BE%8B%E5%AD%90"><span class="toc-text">Vue3中的setup()和ref()函数制作点餐例子</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%AE%8C%E6%95%B4%E5%86%99%E5%AE%8C%E7%82%B9%E9%A4%90%E4%BE%8B%E5%AD%90%EF%BC%8C%E4%BD%BF%E7%94%A8%E6%96%B0%E7%9A%84Vue3%E8%AF%AD%E6%B3%95"><span class="toc-text">完整写完点餐例子，使用新的Vue3语法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%80%BB%E7%BB%93%EF%BC%9AVue3%E4%BB%A3%E7%A0%81%E7%89%B9%E7%82%B9"><span class="toc-text">总结：Vue3代码特点</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8reactive-%E5%87%BD%E6%95%B0%E4%BC%98%E5%8C%96%E4%BB%A3%E7%A0%81"><span class="toc-text">使用reactive()函数优化代码</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#vue3%E6%8F%90%E4%BE%9B%E4%BA%86torefs%E5%87%BD%E6%95%B0"><span class="toc-text">vue3提供了torefs函数</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue3%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">Vue3的生命周期</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#setup"><span class="toc-text">setup</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onBeforeMount"><span class="toc-text">onBeforeMount</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onMounted"><span class="toc-text">onMounted</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onBeforeUpdate"><span class="toc-text">onBeforeUpdate</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onUpdated"><span class="toc-text">onUpdated</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onBeforeUnmount"><span class="toc-text">onBeforeUnmount</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onUnmounted"><span class="toc-text">onUnmounted</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onActivated"><span class="toc-text">onActivated</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#onDeactivated"><span class="toc-text">onDeactivated</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%80%BB%E7%BB%93-1"><span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%92%A9%E5%AD%90%E5%87%BD%E6%95%B0"><span class="toc-text">钩子函数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#vue2%E5%92%8Cvue3%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%AF%B9%E6%AF%94"><span class="toc-text">vue2和vue3生命周期对比</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#onRenderTracked-%E7%8A%B6%E6%80%81%E8%BF%BD%E8%B8%AA"><span class="toc-text">onRenderTracked 状态追踪</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#onRenderTriggered-%E7%8A%B6%E6%80%81%E8%A7%A6%E5%8F%91"><span class="toc-text">onRenderTriggered 状态触发</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue3%E4%B8%ADwatch%E7%9A%84%E4%BD%BF%E7%94%A8%E5%92%8C%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">Vue3中watch的使用和注意事项</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vue3%E4%B8%AD%E6%A8%A1%E5%9D%97%E5%8C%96%E4%BB%8B%E7%BB%8D%EF%BC%8C%E6%97%B6%E9%97%B4%E6%A8%A1%E5%9D%97%E4%BE%8B%E5%AD%90"><span class="toc-text">Vue3中模块化介绍，时间模块例子</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%8B%AC%E7%AB%8B%E6%A8%A1%E5%9D%97%E5%8C%96"><span class="toc-text">独立模块化</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%A8%A1%E5%9D%97%E5%8C%96%E6%94%B9%E8%BF%9B%E4%BE%8B%E5%AD%90"><span class="toc-text">模块化改进例子</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Teleport-%E7%9E%AC%E9%97%B4%E7%A7%BB%E5%8A%A8%E5%87%BD%E6%95%B0%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">Teleport 瞬间移动函数的使用</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%BC%96%E5%86%99%E5%BC%B9%E5%87%BA%E6%A1%86%E7%9A%84%E7%BB%84%E4%BB%B6"><span class="toc-text">编写弹出框的组件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8Teleport%E6%96%B9%E6%B3%95"><span class="toc-text">使用Teleport方法</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Supense-%E5%88%9D%E8%AF%86%E5%BC%82%E6%AD%A5%E8%AF%B7%E6%B1%82%E7%BB%84%E4%BB%B6"><span class="toc-text">Supense 初识异步请求组件</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%BC%96%E5%86%99AsyncShow-vue%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6"><span class="toc-text">编写AsyncShow.vue自定义组件</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#Suspense-%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0%EF%BC%8C%E7%9C%9F%E5%AE%9E%E8%AF%B7%E6%B1%82"><span class="toc-text">Suspense 深入学习，真实请求</span></a></li></ol></li></ol></li></ol>
    </div>
  </section>


  


</aside>



		  
		  <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<script>
  window.pdata={}
  pdata.ispage=false;
  pdata.postTitle="";
  pdata.commentPath="";
  pdata.commentPlaceholder="";
  // header 这里无论是否开启pjax都需要
  var l_header=document.getElementById("l_header");
  
  l_header.classList.add("show");
  
  
    // cover
    var cover_wrapper=document.querySelector('.cover-wrapper');
    
    cover_wrapper.id="none";
    cover_wrapper.style.display="none";
    
  
</script>

        </div>
        
  
  <footer class="footer clearfix">
    <br><br>
    
      
        <div class="aplayer-container">
          


        </div>
      
    
      
        <br>
        <div class="social-wrapper">
          
            
          
            
          
            
          
        </div>
      
    
      
        <div><p>博客内容遵循 <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议</a></p>
</div>
      
    
      
        
          <div><p><span id="lc-sv">本站总访问量为 <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span> 次</span> <span id="lc-uv">访客数为 <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span> 人</span></p>
</div>
        
      
    
      
        本站使用
        <a href="https://github.com/volantis-x/hexo-theme-volantis/tree/4.3.1" target="_blank" class="codename">Volantis</a>
        作为主题
      
    
      
        <div class='copyright'>
        <p><a href="/">Copyright © 2017-2020 XXX</a></p>

        </div>
      
    
  </footer>


        <a id="s-top" class="fas fa-arrow-up fa-fw" href="javascript:void(0)"></a>
      </div>
    </div>
    <div>
      <script>
/************这个文件存放不需要重载的全局变量和全局函数*********/
window.volantis={};
window.volantis.loadcss=document.getElementById("loadcss");
/******************** Pjax ********************************/
function VPjax(){
	this.list=[] // 存放回调函数
	this.start=()=>{
	  for(var i=0;i<this.list.length;i++){
		this.list[i].run();
	  }
	}
	this.push=(fn,name)=>{
		var f=new PjaxItem(fn,name);
		this.list.push(f);
	}
	// 构造一个可以run的对象
	function PjaxItem(fn,name){
		// 函数名称
		this.name = name || fn.name
		// run方法
		this.run=()=>{
			fn()
		}
	}
}
volantis.pjax={}
volantis.pjax.method={
	complete: new VPjax(),
	error: new VPjax(),
	send: new VPjax()
}
volantis.pjax={
	...volantis.pjax,
	push: volantis.pjax.method.complete.push,
	error: volantis.pjax.method.error.push,
	send: volantis.pjax.method.send.push
}
/********************脚本懒加载函数********************************/
// 已经加入了setTimeout
function loadScript(src, cb) {
	setTimeout(function() {
		var HEAD = document.getElementsByTagName('head')[0] || document.documentElement;
		var script = document.createElement('script');
		script.setAttribute('type','text/javascript');
		if (cb) script.onload = cb;
		script.setAttribute('src', src);
		HEAD.appendChild(script);
	});
}
//https://github.com/filamentgroup/loadCSS
var loadCSS = function( href, before, media, attributes ){
	var doc = window.document;
	var ss = doc.createElement( "link" );
	var ref;
	if( before ){
		ref = before;
	}
	else {
		var refs = ( doc.body || doc.getElementsByTagName( "head" )[ 0 ] ).childNodes;
		ref = refs[ refs.length - 1];
	}
	var sheets = doc.styleSheets;
	if( attributes ){
		for( var attributeName in attributes ){
			if( attributes.hasOwnProperty( attributeName ) ){
				ss.setAttribute( attributeName, attributes[attributeName] );
			}
		}
	}
	ss.rel = "stylesheet";
	ss.href = href;
	ss.media = "only x";
	function ready( cb ){
		if( doc.body ){
			return cb();
		}
		setTimeout(function(){
			ready( cb );
		});
	}
	ready( function(){
		ref.parentNode.insertBefore( ss, ( before ? ref : ref.nextSibling ) );
	});
	var onloadcssdefined = function( cb ){
		var resolvedHref = ss.href;
		var i = sheets.length;
		while( i-- ){
			if( sheets[ i ].href === resolvedHref ){
				return cb();
			}
		}
		setTimeout(function() {
			onloadcssdefined( cb );
		});
	};
	function loadCB(){
		if( ss.addEventListener ){
			ss.removeEventListener( "load", loadCB );
		}
		ss.media = media || "all";
	}
	if( ss.addEventListener ){
		ss.addEventListener( "load", loadCB);
	}
	ss.onloadcssdefined = onloadcssdefined;
	onloadcssdefined( loadCB );
	return ss;
};
</script>
<script>
  
  loadCSS("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.14/css/all.min.css", window.volantis.loadcss);
  
  
  
  
</script>
<!-- required -->

<script src="https://cdn.jsdelivr.net/npm/jquery@3.5/dist/jquery.min.js"></script>

<script>
  function pjax_fancybox() {
    $(".md .gallery").find("img").each(function () { //渲染 fancybox
      var element = document.createElement("a"); // a 标签
      $(element).attr("class", "fancybox");
      $(element).attr("pjax-fancybox", "");  // 过滤 pjax
      $(element).attr("href", $(this).attr("src"));
      if ($(this).attr("data-original")) {
        $(element).attr("href", $(this).attr("data-original"));
      }
      $(element).attr("data-fancybox", "images");
      var caption = "";   // 描述信息
      if ($(this).attr('alt')) {  // 判断当前页面是否存在描述信息
        $(element).attr('data-caption', $(this).attr('alt'));
        caption = $(this).attr('alt');
      }
      var div = document.createElement("div");
      $(div).addClass("fancybox");
      $(this).wrap(div); // 最外层套 div ，其实主要作用还是 class 样式
      var span = document.createElement("span");
      $(span).addClass("image-caption");
      $(span).text(caption); // 加描述
      $(this).after(span);  // 再套一层描述
      $(this).wrap(element);  // 最后套 a 标签
    })
    $(".md .gallery").find("img").fancybox({
      selector: '[data-fancybox="images"]',
      hash: false,
      loop: false,
      closeClick: true,
      helpers: {
        overlay: {closeClick: true}
      },
      buttons: [
        "zoom",
        "close"
      ]
    });
  };
  function SCload_fancybox() {
    if ($(".md .gallery").find("img").length == 0) return;
    loadCSS("https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css", document.getElementById("loadcss"));
    loadScript('https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js', pjax_fancybox)
  };
  $(function () {
    SCload_fancybox();
  });
  function Pjax_SCload_fancybox(){
	if (typeof $.fancybox == "undefined") {
	 SCload_fancybox();
    } else {
	 pjax_fancybox();
    }
  }
  volantis.pjax.push(Pjax_SCload_fancybox)
  volantis.pjax.send(()=>{
      if (typeof $.fancybox != "undefined") {
        $.fancybox.close();    // 关闭弹窗
      }
  },'fancybox')
</script>


<!-- internal -->



  
  

  <div id="rightmenu-wrapper">
    <ul class="list-v rightmenu" id="rightmenu-content">
      <li class='option'>
        <a class='vlts-menu opt fix-cursor-default' id='menu-copy-text' onclick="document.execCommand('copy')"><i class='fa fa-copy fa-fw'></i>复制文本</a>
        <hr id='hr-text'>
        <a class='vlts-menu opt fix-cursor-default' id='menu-copy-href'><i class='fa fa-link fa-fw'></i>复制链接</a>
        <a class='vlts-menu opt fix-cursor-default' id='menu-open-href'><i class='fa fa-external-link-square-alt fa-fw'></i>在新标签页打开</a>
        <hr id='hr-href'>
        <a class='vlts-menu opt fix-cursor-default' id='menu-copy-src'><i class='fa fa-image fa-fw'></i>复制图片地址</a>
        <hr id='hr-src'>
      </li>
      
        <li class='navigation'>
          <a class='nav icon-only fix-cursor-default' onclick='history.back()'><i class='fa fa-arrow-left fa-fw'></i></a>
          <a class='nav icon-only fix-cursor-default' onclick='history.forward()'><i class='fa fa-arrow-right fa-fw'></i></a>
          <a class='nav icon-only fix-cursor-default' onclick='window.location.reload()'><i class='fa fa-redo fa-fw'></i></a>
          <a class='nav icon-only fix-cursor-default' href='/'><i class='fa fa-home fa-fw'></i></a>
        </li>
      
      <hr>
      
        
      
        
          <hr>
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' href=https://volantis.js.org/faqs/
        
        
        
        
          id="https:volantisjsorgfaqs"
        >
        <i class='fa fa-question fa-fw'></i> 常见问题
      </a>
    </li>
  
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' href=https://volantis.js.org/examples/
        
        
        
        
          id="https:volantisjsorgexamples"
        >
        <i class='fa fa-rss fa-fw'></i> 示例博客
      </a>
    </li>
  
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' href=https://volantis.js.org/contributors/
        
        
        
        
          id="https:volantisjsorgcontributors"
        >
        <i class='fa fa-fan fa-spin fa-fw'></i> 加入社区
      </a>
    </li>
  
        
      
        
          <hr>
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' href=https://github.com/volantis-x/volantis-docs/
        
        
        
        
          id="https:githubcomvolantis-xvolantis-docs"
        >
        <i class='fa fa-code-branch fa-fw'></i> 本站源码
      </a>
    </li>
  
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' href=https://github.com/volantis-x/hexo-theme-volantis/
        
        
        
        
          id="https:githubcomvolantis-xhexo-theme-volantis"
        >
        <i class='fa fa-code-branch fa-fw'></i> 主题源码
      </a>
    </li>
  
        
      
        
          <hr>
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' 
        
        
        
          onclick="document.execCommand('print')"
        
        >
        <i class='fa fa-print fa-fw'></i> 打印页面
      </a>
    </li>
  
        
      
        
          
    <li>
      <a class='vlts-menu fix-cursor-default ' 
        
        
        
        >
        <i class='fa fa-moon fa-fw'></i> 暗黑模式
      </a>
    </li>
  
        
      
        
      
    </ul>
  </div>

  <script>
    window.document.oncontextmenu = function (event) {
      if (event.ctrlKey) return true;
      if (/Android|webOS|BlackBerry/i.test(navigator.userAgent)) return true;
      return popMenu(event);
    };
    document.addEventListener("click", function (event) {
      var mymenu = document.getElementById('rightmenu-wrapper');
      mymenu.style.display = "none";
    });
    function popMenu(event) {
      var mymenu = document.getElementById('rightmenu-wrapper');
      var menuContent = document.getElementById('rightmenu-content');
      var screenWidth = document.documentElement.clientWidth || document.body.clientWidth;
      var screenHeight = document.documentElement.clientHeight || document.body.clientHeight;
      mymenu.style.left = event.clientX + "px"; // 获取鼠标位置
      mymenu.style.top = event.clientY + "px";
      mymenu.style.display = 'block';
      if (event.clientX * 2 > screenWidth) {
        menuContent.classList.add('left');
      } else {
        menuContent.classList.remove('left');
      }
      if (event.clientY * 2 > screenHeight) {
        menuContent.classList.add('top');
      } else {
        menuContent.classList.remove('top');
      }

      let hrText = document.getElementById('hr-text');
      let hrSrc = document.getElementById('hr-src');
      let hrHref = document.getElementById('hr-href');

      // 选中图片
      let copySrc = document.getElementById('menu-copy-src');
      if (copySrc != undefined) {
        if (event.target.currentSrc) {
          copySrc.style.display = 'block';
          copySrc.addEventListener("click", function (e) {
            copyString(event.target.currentSrc);
          },{once: true});
          hrSrc.style.display = 'block';
        } else {
          copySrc.style.display = 'none';
          hrSrc.style.display = 'none';
        }
      }

      // 选中按钮
      // 判断是不是按钮
      let href = '';
      if (event.path) {
        for (i = 0; i < event.path.length; i++) {
          if (event.path[i].href != undefined && event.path[i].href.length > 0) {
            href = event.path[i].href;
          }
        }
      }

      let copyText = document.getElementById('menu-copy-text');
      copyText.style.display = 'none';
      hrText.style.display = 'none';
      if (href.length == 0) {
        // 选中文本
        if (window.getSelection().toString()) {
          if ('' == 'true') {
            copyText.style.display = 'block';
            hrText.style.display = 'block';
          }
        }
      }

      // 在新标签页打开
      let openHref = document.getElementById('menu-open-href');
      if (openHref != undefined) {
        if (href.length > 0) {
          openHref.style.display = 'block';
          openHref.addEventListener("click", function (e) {
            window.open(href);
          },{once: true});
          hrHref.style.display = 'block';
        } else {
          openHref.style.display = 'none';
          hrHref.style.display = 'none';
        }
      }
      // 复制链接
      let copyHref = document.getElementById('menu-copy-href');
      if (copyHref != undefined) {
        if (href.length > 0) {
          copyHref.style.display = 'block';
          copyHref.addEventListener("click", function (e) {
            copyString(href);
          },{once: true});
        } else {
          copyHref.style.display = 'none';
        }
      }
      // 有音乐播放器 see: layout/_third-party/aplayer/script.ejs
      
      return false; // 该行代码确保系统自带的右键菜单不会被调出
    }
    function hideMenu() {
      document.getElementById('rightmenu-wrapper').style.display = 'none';
    }
    function copyString(str) {
      const input = document.createElement('input');
      input.setAttribute('readonly', 'readonly');
      document.body.appendChild(input);
      input.setAttribute('value', str);
      input.select();
      document.execCommand('copy');
      document.body.removeChild(input);
    }
    document.execCommand('click');
  </script>




<script>
  function loadIssuesJS() {
    if ($(".md").find(".issues-api").length == 0) return;
	
	  loadScript('/blog/js/issues.js');
	
  };
  $(function () {
    loadIssuesJS();
  });
  volantis.pjax.push(()=>{
	if (typeof IssuesAPI == "undefined") {
	  loadIssuesJS();
	}
  },"IssuesJS")
</script>



  <script defer src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@17.1.0/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  

<script>
  window.FPConfig = {
	delay: 0,
	ignoreKeywords: [],
	maxRPS: 5,
	hoverDelay: 25
  };
</script>
<script defer src="https://cdn.jsdelivr.net/gh/gijo-varghese/flying-pages@2.1.2/flying-pages.min.js"></script>











  
  
<script src="/blog/js/valine.js"></script>


<script>
  function emoji(path, idx, ext) {
    return path + "/" + path + "-" + idx + "." + ext;
  }
  var emojiMaps = {};
  for (var i = 1; i <= 54; i++) {
    emojiMaps['tieba-' + i] = emoji('tieba', i, 'png');
  }
  for (var i = 1; i <= 101; i++) {
    emojiMaps['qq-' + i] = emoji('qq', i, 'gif');
  }
  for (var i = 1; i <= 116; i++) {
    emojiMaps['aru-' + i] = emoji('aru', i, 'gif');
  }
  for (var i = 1; i <= 125; i++) {
    emojiMaps['twemoji-' + i] = emoji('twemoji', i, 'png');
  }
  for (var i = 1; i <= 4; i++) {
    emojiMaps['weibo-' + i] = emoji('weibo', i, 'png');
  }
  function pjax_valine() {
    if(!document.querySelectorAll("#valine_container")[0])return;
    let pagePlaceholder = pdata.commentPlaceholder || "快来评论吧~";
    let path = pdata.commentPath;
    if (path.length == 0) {
      let defaultPath = '';
      path = defaultPath || decodeURI(window.location.pathname);
    }
    var valine = new Valine();
    valine.init(Object.assign({"path":null,"placeholder":"快来评论吧~","appId":null,"appKey":null,"meta":["nick","mail","link"],"requiredFields":["nick","mail"],"enableQQ":true,"recordIP":false,"avatar":"robohash","pageSize":10,"lang":"zh-cn","highlight":true,"mathJax":false}, {
      el: '#valine_container',
      path: path,
      placeholder: pagePlaceholder,
      emojiCDN: 'https://cdn.jsdelivr.net/gh/volantis-x/cdn-emoji/valine/',
      emojiMaps: emojiMaps,
    }))
  }
  $(function () {
    pjax_valine();
  });
  volantis.pjax.push(pjax_valine);
</script>






  
<script src="/blog/js/app.js"></script>



<!-- optional -->

  <script>
const SearchServiceimagePath="https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/img/";
const ROOT =  ("/blog/" || "/").endsWith('/') ? ("/blog/" || "/") : ("/blog//" || "/" );

$('.input.u-search-input').one('focus',function(){
	
		loadScript('/blog/js/search/hexo.js',setSearchService);
	
})

function listenSearch(){
  
    customSearch = new HexoSearch({
      imagePath: SearchServiceimagePath
    });
  
}
function setSearchService() {
	listenSearch();
	
}
</script>











  <script defer>

  const LCCounter = {
    app_id: 'u9j57bwJod4EDmXWdxrwuqQT-MdYXbMMI',
    app_key: 'jfHtEKVE24j0IVCGHbvuFClp',
    custom_api_server: '',

    // 查询存储的记录
    getRecord(Counter, url, title) {
      return new Promise(function (resolve, reject) {
        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({url})))
          .then(resp => resp.json())
          .then(({results, code, error}) => {
            if (code === 401) {
              throw error;
            }
            if (results && results.length > 0) {
              var record = results[0];
              resolve(record);
            } else {
              Counter('post', '/classes/Counter', {url, title: title, times: 0})
                .then(resp => resp.json())
                .then((record, error) => {
                  if (error) {
                    throw error;
                  }
                  resolve(record);
                }).catch(error => {
                console.error('Failed to create', error);
                reject(error);
              });
            }
          }).catch((error) => {
          console.error('LeanCloud Counter Error:', error);
          reject(error);
        });
      })
    },

    // 发起自增请求
    increment(Counter, incrArr) {
      return new Promise(function (resolve, reject) {
        Counter('post', '/batch', {
          "requests": incrArr
        }).then((res) => {
          res = res.json();
          if (res.error) {
            throw res.error;
          }
          resolve(res);
        }).catch((error) => {
          console.error('Failed to save visitor count', error);
          reject(error);
        });
      });
    },

    // 构建自增请求体
    buildIncrement(objectId) {
      return {
        "method": "PUT",
        "path": `/1.1/classes/Counter/${ objectId }`,
        "body": {
          "times": {
            '__op': 'Increment',
            'amount': 1
          }
        }
      }
    },

    // 校验是否为有效的 UV
    validUV() {
      var key = 'LeanCloudUVTimestamp';
      var flag = localStorage.getItem(key);
      if (flag) {
        // 距离标记小于 24 小时则不计为 UV
        if (new Date().getTime() - parseInt(flag) <= 86400000) {
          return false;
        }
      }
      localStorage.setItem(key, new Date().getTime().toString());
      return true;
    },

    addCount(Counter) {
      var enableIncr = '' === 'true' && window.location.hostname !== 'localhost';
      enableIncr = true;
      var getterArr = [];
      var incrArr = [];
      // 请求 PV 并自增
      var pvCtn = document.querySelector('#lc-sv');
      if (pvCtn || enableIncr) {
        var pvGetter = this.getRecord(Counter, 'http://shouyeren24.gitee.io' + '/#lc-sv', 'Visits').then((record) => {
          incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-sv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + 1;
              if (pvCtn) {
                pvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(pvGetter);
      }

      // 请求 UV 并自增
      var uvCtn = document.querySelector('#lc-uv');
      if (uvCtn || enableIncr) {
        var uvGetter = this.getRecord(Counter, 'http://shouyeren24.gitee.io' + '/#lc-uv', 'Visitors').then((record) => {
          var vuv = this.validUV();
          vuv && incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-uv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + (vuv ? 1 : 0);
              if (uvCtn) {
                uvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(uvGetter);
      }

      // 请求文章的浏览数，如果是当前页面就自增
      var allPV = document.querySelectorAll('#lc-pv');
      if (allPV.length > 0 || enableIncr) {
        for (i = 0; i < allPV.length; i++) {
          let pv = allPV[i];
          let title = pv.getAttribute('data-title');
          var url = 'http://shouyeren24.gitee.io' + pv.getAttribute('data-path');
          if (url) {
            var viewGetter = this.getRecord(Counter, url, title).then((record) => {
              // 是当前页面就自增
              let curPath = window.location.pathname;
              if (curPath.includes('index.html')) {
                curPath = curPath.substring(0, curPath.lastIndexOf('index.html'));
              }
              if (pv.getAttribute('data-path') == curPath) {
                incrArr.push(this.buildIncrement(record.objectId));
              }
              if (pv) {
                var ele = pv.querySelector('#lc-pv #number');
                if (ele) {
                  if (pv.getAttribute('data-path') == curPath) {
                    ele.innerText = (record.times || 0) + 1;
                  } else {
                    ele.innerText = record.times || 0;
                  }
                  pv.style.display = 'inline';
                }
              }
            });
            getterArr.push(viewGetter);
          }
        }
      }

      // 如果启动计数自增，批量发起自增请求
      if (enableIncr) {
        Promise.all(getterArr).then(() => {
          incrArr.length > 0 && this.increment(Counter, incrArr);
        })
      }

    },


    fetchData(api_server) {
      var Counter = (method, url, data) => {
        return fetch(`${ api_server }/1.1${ url }`, {
          method,
          headers: {
            'X-LC-Id': this.app_id,
            'X-LC-Key': this.app_key,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      this.addCount(Counter);
    },

    refreshCounter() {
      var api_server = this.app_id.slice(-9) !== '-MdYXbMMI' ? this.custom_api_server : `https://${ this.app_id.slice(0, 8).toLowerCase() }.api.lncldglobal.com`;
      if (api_server) {
        this.fetchData(api_server);
      } else {
        fetch('https://app-router.leancloud.cn/2/route?appId=' + this.app_id)
          .then(resp => resp.json())
          .then(({api_server}) => {
            this.fetchData('https://' + api_server);
          });
      }
    }

  };

  LCCounter.refreshCounter();

  document.addEventListener('pjax:complete', function () {
    LCCounter.refreshCounter();
  });
</script>




  <script>
const rootElement = document.documentElement;
const darkModeStorageKey = "user-color-scheme";
const rootElementDarkModeAttributeName = "data-user-color-scheme";

const setLS = (k, v) => {
    localStorage.setItem(k, v);
};

const removeLS = (k) => {
    localStorage.removeItem(k);
};

const getLS = (k) => {
    return localStorage.getItem(k);
};

const getModeFromCSSMediaQuery = () => {
  return window.matchMedia("(prefers-color-scheme: dark)").matches
    ? "dark"
    : "light";
};

const resetRootDarkModeAttributeAndLS = () => {
  rootElement.removeAttribute(rootElementDarkModeAttributeName);
  removeLS(darkModeStorageKey);
};

const validColorModeKeys = {
  dark: true,
  light: true,
};

const applyCustomDarkModeSettings = (mode) => {
  const currentSetting = mode || getLS(darkModeStorageKey);

  if (currentSetting === getModeFromCSSMediaQuery()) {
    resetRootDarkModeAttributeAndLS();
  } else if (validColorModeKeys[currentSetting]) {
    rootElement.setAttribute(rootElementDarkModeAttributeName, currentSetting);
  } else {
    resetRootDarkModeAttributeAndLS();
  }
};

const invertDarkModeObj = {
  dark: "light",
  light: "dark",
};

/**
 * get target mode
 */
const toggleCustomDarkMode = () => {
  let currentSetting = getLS(darkModeStorageKey);

  if (validColorModeKeys[currentSetting]) {
    currentSetting = invertDarkModeObj[currentSetting];
  } else if (currentSetting === null) {
    currentSetting = invertDarkModeObj[getModeFromCSSMediaQuery()];
  } else {
    return;
  }
  setLS(darkModeStorageKey, currentSetting);
  return currentSetting;
};

/**
 * bind click event for toggle button
 */
var btn=$("#wrapper .toggle-mode-btn,#rightmenu-wrapper .toggle-mode-btn");
function bindToggleButton() {
    btn.on('click',(e) => {
      const mode = toggleCustomDarkMode();
      applyCustomDarkModeSettings(mode);
    });
}

applyCustomDarkModeSettings();
document.addEventListener("DOMContentLoaded", bindToggleButton);
volantis.pjax.push(bindToggleButton);
volantis.pjax.send(()=>{
	btn.unbind('click');
},'toggle-mode-btn-unbind');
</script>








<script>
function listennSidebarTOC() {
  const navItems = document.querySelectorAll(".toc li");
  if (!navItems.length) return;
  const sections = [...navItems].map((element) => {
    const link = element.querySelector(".toc-link");
    const target = document.getElementById(
      decodeURI(link.getAttribute("href")).replace("#", "")
    );
    link.addEventListener("click", (event) => {
      event.preventDefault();
      window.scrollTo({
		top: target.offsetTop + 100,
		
		behavior: "smooth"
		
	  });
    });
    return target;
  });

  function activateNavByIndex(target) {
    if (target.classList.contains("active-current")) return;

    document.querySelectorAll(".toc .active").forEach((element) => {
      element.classList.remove("active", "active-current");
    });
    target.classList.add("active", "active-current");
    let parent = target.parentNode;
    while (!parent.matches(".toc")) {
      if (parent.matches("li")) parent.classList.add("active");
      parent = parent.parentNode;
    }
  }

  function findIndex(entries) {
    let index = 0;
    let entry = entries[index];
    if (entry.boundingClientRect.top > 0) {
      index = sections.indexOf(entry.target);
      return index === 0 ? 0 : index - 1;
    }
    for (; index < entries.length; index++) {
      if (entries[index].boundingClientRect.top <= 0) {
        entry = entries[index];
      } else {
        return sections.indexOf(entry.target);
      }
    }
    return sections.indexOf(entry.target);
  }

  function createIntersectionObserver(marginTop) {
    marginTop = Math.floor(marginTop + 10000);
    let intersectionObserver = new IntersectionObserver(
      (entries, observe) => {
        let scrollHeight = document.documentElement.scrollHeight + 100;
        if (scrollHeight > marginTop) {
          observe.disconnect();
          createIntersectionObserver(scrollHeight);
          return;
        }
        let index = findIndex(entries);
        activateNavByIndex(navItems[index]);
      },
      {
        rootMargin: marginTop + "px 0px -100% 0px",
        threshold: 0,
      }
    );
    sections.forEach((element) => {
      element && intersectionObserver.observe(element);
    });
  }
  createIntersectionObserver(document.documentElement.scrollHeight);
}

document.addEventListener("DOMContentLoaded", listennSidebarTOC);
document.addEventListener("pjax:success", listennSidebarTOC);
</script>

<!-- more -->

 
	   
	    


<script src="https://cdn.jsdelivr.net/npm/pjax@0.2.8/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox])',
        selectors: [
          "title",
          
          "#pjax-container",
          "#pjax-header-nav-list"
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      window.subData = null; // 移除标题（用于一二级导航栏切换处）

      volantis.$switcher.removeClass('active'); // 关闭移动端激活的搜索框
      volantis.$header.removeClass('z_search-open'); // 关闭移动端激活的搜索框
      volantis.$wrapper.removeClass('sub'); // 跳转页面时关闭二级导航

      // 解绑事件 避免重复监听
      volantis.$topBtn.unbind('click');
      $('.menu a').unbind('click');
      $(window).unbind('resize');
      $(window).unbind('scroll');
      $(document).unbind('scroll');
      $(document).unbind('click');
      $('body').unbind('click');
	  // 使用 volantis.pjax.send 方法传入pjax:send回调函数 参见layout/_partial/scripts/global.ejs
	  volantis.pjax.method.send.start();
    });

    document.addEventListener('pjax:complete', function () {
      $('.nav-main').find('.list-v').not('.menu-phone').removeAttr("style",""); // 移除小尾巴的移除
      $('.menu-phone.list-v').removeAttr("style",""); // 移除小尾巴的移除
      $('script[data-pjax], .pjax-reload script').each(function () {
        $(this).parent().append($(this).remove());
      });
      try{
		// 使用 volantis.pjax.push 方法传入重载函数 参见layout/_partial/scripts/global.ejs
		volantis.pjax.method.complete.start();
      } catch (e) {
        console.log(e);
      }
    });

    document.addEventListener('pjax:error', function (e) {
	  // 使用 volantis.pjax.error 方法传入pjax:error回调函数 参见layout/_partial/scripts/global.ejs
	  volantis.pjax.method.error.start();
      window.location.href = e.triggerElement.href;
    });
</script>
 
	  
    </div>
  </body>
</html>
